How would you set up the routing in ASP.NET MVC in order to route paths with undefined controllers to a specific controller.
For example, I have a UserController, so I would want http://example.com/user to route to the UserController, but I would want http://example.com/supercoolproject to route to the ProjectController in order to find the Super Cool Project item
I believe you shouldn't use http://example.com/supercoolproject address. Instead, it should be http://example.com/project/supercool, but if you want to use address in http://example.com/{projectname}project format, you can define rule in global.asax like this:
routes.MapRoute(
"ProductByNameRule",
"{projectName}project",
new { controller = "Project", action = "ByName" }
);
and have
public ActionResult ByName(string projectName) {
}
in ProjectController.
You can create a custom controller factory to do this.
http://keyvan.io/custom-controller-factory-in-asp-net-mvc
In the CreateController method of the custom controller factory's IControllerFactory implementation first try to create the controller using DefaultControllerFactory, then if this fails create an instance of your fallback controller and return it instead.
Related
I want to decide where to send each url at runtime.
I don't want to use attributes like [Route("/hello")] and I don't want to use the conventional [controller=hello]/[action=Index]. What I want is a way to execute a specific controller after deciding with my own logic like this
if(context.Request.Path.Value == "/hello"){
SomehowCallTheActionOnController("MyController", "MyAction", anyUrlValuesLikeId);
}
Using the DynamicRouteValueTransformer, I can get the dictionary of values such as values["controller"]="home"; But since I want to catch all, in my case I only get "values["all"]="hello/this/is/my/url", even if I set the controller name manually, it won't work because I don't want to use the conventional mapping of controllers and actions.
I guess what I'm trying to do is the equivalent of Route::get('/user', [UserController::class, 'index']); in laravel for example; use my own routing but let asp pass dependency injections to controllers and instantiate ActionContext for me. Is this possible at all in ASP.NET?
I can just use
app.MapGet("myroute", async context => {
var actionContext = new ActionContext(context, context.getRouteData(), new ActionRequest());
await new ContentResult(){ Content = "hi" }.ExecuteResultAsync(actionContext);
})
and manage dependency injections on my own by GetService... but I'm not sure this is how it's supposed to be done because the actionRequest for example won't have all necessary properties set up, and asp might be using it for something??
Anyway, thanks in advance :)
I found the issue. When you specify the controller name for the route, you must not include the word "Controller"!
Like this:
app.MapControllerRoute(
"About",
"/About/{something}",
defaults: new { controller = "App", action = "Index" }
);
and the controller name is "AppController" with a method "Index" like this
public class AppController : Controller {
public IActionResult Index(string something) {
return /* put your result here */;
}
}
I still don't know how to specify a method (GET, POST, etc) with "MapControllerRoute" but at least this way I can specify routes from an array with templates and names...
So I have a HomeController, to access it along with Actions I have to type url.com/home/action.
Would it be possible to change this to something else like url.com/anothernamethatpointstohomeactually/action?
I suggest you to use attribute routing, but of course it depends on your scenario.
[Route("prefix")]
public class Home : Controller {
[HttpGet("name")]
public IActionResult Index() {
}
}
This will be found at url.com/prefix/name
There are a lot of options to attribute routing, some samples:
[Route("[controller]")] // there are placeholders for common patterns
as [area], [controller], [action], etc.
[HttpGet("")] // empty is valid. url.com/prefix
[Route("")] // empty is valid. url.com/
[HttpGet("/otherprefix/name")] // starting with / won't use the route prefix
[HttpGet("name/{id}")]
public IActionResult Index(int id){ ... // id will bind from route param.
[HttpGet("{id:int:required}")] // you can add some simple matching rules too.
Check Attribute Routing official docs
You can add new Routes in your Startup.Configure method within your app.UseMvc(routes => block:
routes.MapRoute(
name: "SomeDescriptiveName",
template: "AnotherNameThatPointsToHome/{action=Index}/{id?}",
defaults: new { controller = "Home"}
);
The code is quite similar to ASP.NET MVC.
For more info, see Routing in ASP.NET Core.
Below is for ASP.NET MVC (not ASP.NET Core MVC)
You can also add a new Route via routes.MapRoute in your RouteConfig:
routes.MapRoute(
name: "SomeDescriptiveName",
url: "AnotherNameThatPointsToHome/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
Make sure, you insert the code before you define your Default route.
For more information, visit the docs.
Using the Route attribute on top of your controller will allow you to define the route on the entire controller.
[Route("anothernamethatpointstohomeactually")]
You can read more here.
In ASP.NET Core 6, we just do that in one line.
Go to your Controller and write before your action method:
[Route("YourController/YourAction/{YourParameter?}")]
In your example, you you need to write like this:
[Route("Home/Index/{name?}")]
You can change your url by modifying your routing configuration.
It is kind of like htaccess but not really.
https://learn.microsoft.com/en-us/aspnet/mvc/overview/older-versions-1/controllers-and-routing/creating-custom-routes-cs
Another solution is to create a page and do a server redirect.
Server.Transfer
I just checked attribute routing in ASP.NET Web API 2. In that I can use RoutePrefix attribute at class level to set prefix to all action name URL. Mostly I use action name as URL routing for particular action. Is there any way that I write a single line of code which set action name as default value for Route attribute for all action? I want that because I am using action name as URI template, so it will be duplication on top of each action name.
[RoutePrefix("api")]
//[Route("{action}")] // Possible I could write like this
public class BooksController : ApiController
{
[Route("GetBooks")] //Route value same as action name, http://localhost:xxxx/api/GetBooks
public object GetBooks() { ... }
[Route("CreateBook")] //Route value same as action name, http://localhost:xxxx/api/CreateBook
[HttpPost]
public object CreateBook(Book book) { ... }
}
EDIT 1: I want to use attribute routing because I want web API URL pattern like this http://hostname/api/action_name. My application uses single API controller, so I don't want controller name as part of action URI.
Solution: [Route("{action}")] on class level will work, if you remove route attribute from all other action unless you want to override for any action.
Personally I would just not use attribute routing and instead use the standard route mapping. So in your App_Start/RouteConfig.cs file:
routes.MapRoute(
name: "Api",
url: "api/{action}",
defaults: new { controller = "Books" }
);
This question suddenly pops up in my mind.
In Startup.cs I have:
HttpConfiguration config = new HttpConfiguration();
config.MapHttpAttributeRoutes();
app.UseWebApi(config);
When I have a method like this one:
[RoutePrefix("api/Order")]
public class OrderController : ApiController
{
// don't use any attribute here
public IHttpActionResult HelloWorld()
{
...
return Ok();
}
}
Is it possible to access HelloWorld()?
Should a GET or POST or whatever action be sent?
You can access to HttpWorld() using GET if you rename your method as: GetHelloWorld().
The same with POST renaming to PostHelloWorld().
But I prefer using [HttpGet], [HttpPost], ... attributes, even if my action methods has the "Get" or "Post" characters in the name, to avoid possible errors.
Updated
After making some tests, I realised that my comments about that is not possible to call the HelloWorld are not correct.
Indeed it is possible to call your HelloWorld() method if you make a POST call to http://<YourProjectUrl>/order.
So, the default method will be POST and, as you haven't configured any Route for your action method (take in account that RoutePrefix is just a prefix, so needs a Route attribute to be considered), it will get your controller name without "Controller" (OrderController -> Order).
I have Custom routing for my application as shown bellow
Application Name is ValidationTest and i do changed my default binding to following .
That works fine , But i do have some Actions in Controller class , and i do use urlHelper to Identify the Action Path and Controller path You can see that in the Bottom code , But after i changed the default routing it throws me exception While trying to read action from url helper , and i am new to mvc so please suggest me how to give the path to Controller and Action
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
"MyRout",// Route name
"RubinsApp/{CRM}/{id}",// URL with parameters
new {
controller = "Render",
action = "RenderApp",
id = UrlParameter.Optional
} // Parameter defaults
);
}
so my url is
http://localhost/ValidationTest/RubinsApp/crm/test
so
ValidationTest=Application Name
RubinsApp/CRM =Routing Para
test=id
and this works Fine
My Problem is, I have an Ajax Action Call Where The Action URl was Defined Like Bellow
in cshtml
UrlHelper urm = new UrlHelper(Request.RequestContext);
var urlsMenu = urm.Action("BuildNavigationMenu", "Render").ToString(); //This Thorws Object null Error
Here
BuildNavigationMenu=Action Name
Render= Controller
In your custom route you have removed the {action} token meaning that you can no longer specify any other action than the one defined by default which is RenderApp. That's why the urlHelper.Action method returns null.
The way you have defined your routes, in this application you could only ever execute a single action (RenderApp) on a single controller (Render). In your urlHelper.Action call you are attempting to invoke the BuildNavigationMenu action but obviously that's impossible as this action can never be reached.
So you will have to modify your "RubinsApp/{CRM}/{id}" route to include at least the {action} token somewhere. Or add another route definition after it.
And just a side-note about your code. If you are writing this inside a controller action you don't need to instantiate a new UrlHelper. The Controller class already has a Url property:
public ActionResult Foo()
{
var urlsMenu = Url.Action("BuildNavigationMenu", "Render");
...
}