Multiple controllers, same same controller name - c#

I was wondering if this is possible. Say I have a monolithic Controller, ReportController.cs.
I want to make a totally separate controller file but still keep the /Report/ in the url that we've some to know and expect.
What I tried was this in my global asax:
routes.MapRoute(
"Testing", // Route name
"{test}/{action}/{id}" // URL with parameters
);
and I added a new Controller named ReportTest.cs
the original route looks like this:
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "LandingPage", action = "Index", id = UrlParameter.Optional } // Parameter defaults
);
Every time I try to call the simple action I have in ReportTest.cs I get this error: "Value cannot be null or empty. Parameter name: controllerName"
Am I misunderstanding how this works. When you have "{controller}/.." is this not saying 'look for any controllers named + controller and use that'. So if I go to .../Report/DoStuff it'll look for the method DoStuff on ReportController right?
So wouldn't my other route just append a search sequence? So if I put .../Report/DoStuff it'll look for the method DoStuff on ReportController and ReportTest right?

The routing format string:
{controller}/{action}/{id}
Means: the first part ("part" being "element after splitting on /") of the request URI is the controller name, the next part the action method and the last part the ID.
The placeholders {controller} and {action} are special. So your route {test}/{action}/{id} will not find any controller, as none is specified, and {test} doesn't mean anything. (Well it does, it'll get added as a route attribute named "test", and assigned a value representing that part of the request URI, so that is irrelevant for this scenario).
If you want to route an URI to a controller that is not mentioned in the URI, then you must literally specify the prefix, and the controller it should be routed to.
So your routing will look like this:
routes.MapRoute(
"SecondReportController",
"Report/NotOnReportController/{id}",
new { controller = "NotAReportController" }
);
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "LandingPage", action = "Index", id = UrlParameter.Optional } // Parameter defaults
);
Then you can use the following controller:
public class NotAReportController : Controller
{
public ActionResult NotOnReportController(int id)
{
// ...
}
}
You can of course also use attribute routing instead:
public class NotAReportController : Controller
{
[Route("Report/NotOnReportController/{id}")]
public ActionResult NotOnReportController(int id)
{
// ...
}
}

Related

How to solve 'MapRoute uses'. {controller}/{name} taking all action call in same route

I am using
'routes.MapRoute'
to take one parameter without calling the action name. it works fine, but now my problem is whenever I wanted to use any other action form the same controller it's always calling the same action that is described on the 'routes.MapRoute'.
My ajax calling for all other action has GET type. but still, it's calling the same action that is described in the routes.MapRoute.
//This is my custom route.
routes.MapRoute(
"kuenstler",
"kuenstler/{name}",
new { controller = "kuenstler", action = "Index" }
);
//my default route
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Site", action = "Index", id
=
UrlParameter.Optional }
);
The first route will be called from a link attribute from another page so I need to get the name from there but without the action name.
link
action that needs to get the name from the calling.
public ActionResult Index(string name)
{
return View();
}
[HttpGet]
public ActionResult GetKuenstlerGalleryData(int? artistId, string
direction)
{
/// some code
}
Every time I am clicking the link
//localhost:50519/Kuenstler/firstname-lastname.
I am getting the name in my Index. Then I am calling the second action from javascript with GET type. But every time it's coming in the Index with the calling action name as parameter.
But every time it's coming in the Index with the calling action name as parameter.
Of course it does, your requests path perfectly fits the kuenstler route template.
You can map specific route for GetKuenstlerGalleryData action right before 'kuenstler' one. Ex.
routes.MapRoute(
"kuenstler-gallery-data",
"kuenstler/GetKuenstlerGalleryData",
new { controller = "kuenstler", action = "GetKuenstlerGalleryData" }
);
routes.MapRoute(
"kuenstler",
"kuenstler/{name}",
new { controller = "kuenstler", action = "Index" }
);
or use separate template, ex.
routes.MapRoute(
"kuenstler-gallery-data",
"kuenstler-gallery-data",
new { controller = "kuenstler", action = "GetKuenstlerGalleryData" }
);
or even use attribute routing

Anyway to have an action be anything in the RouteConfig in MVC and not having to specify a specific one?

So I have a controller that holds about 10 actions. Each action/view just simply holds an image. What I'm trying to do is have a parameter sent to the URL for each action (the parameter does the same thing for each action).
routes.MapRoute(
name: "MyRoute",
url: "MyController/{action}/{myparameter}",
defaults: new { controller = "MyController", action = "CanIMakeThisBeAnything", myparameter = UrlParameter.Optional }
);
Is there anyway I can make the action take in any action in the controller so I don't have to specify 10 different routes?
If I understand your comments correctly, you want to make the route look like:
routes.MapRoute("MyRoute", "{controller}/{action}/{myparameter}",
new
{
controller = "My",
action = "CanIMakeThisBeAnything",
myparameter = UrlParameter.Optional
});
And your action(s) like:
public ActionResult YesYouCanMakeThisAnything(string myparameter)
{
...
return View(...);
}
So if someone navigated to yourwebapp/My/YesYouCanMakeThisAnything/abc123, then it would call the above action and myparameter would equal "abc123".
If someone navigated to simply yourwebapp, then it would call the action named "CanIMakeThisBeAnything" (specified in your defaults for the route) on the controller "MyController" (also specified in your defaults for the route) and myparameter would equal null (because it has no default and is optional).

How to set up routing so that Index does show?

So I know google can penalize a site if you have the same content on multiple urls... unfortunately, in MVC this is too common i can have example.com/, example.com/Home/ and example.com/Home/Index and all three urls would take me to the same page... so how do I make sure that whenever Index is in the url, that it redirects to the same without the Index and of course the same thing with the Home
Perhaps this little library may be useful for you.
This library is not very convinient in your case, but it should work.
var route = routes.MapRoute(name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional });
routes.Redirect(r => r.MapRoute("home_index", "/home/index")).To(route);
routes.Redirect(r => r.MapRoute("home", "/home")).To(route);
The way I handle this is for default pages like Index is to simply create an explicit route for only one of them. I.e. "example.com/People" would be the route for People/Index, and there would be no valid page at the url "/example.com/People/Index".
The Home example is unique in that it has potentially three different URLs. Again in this case I'd simply create a route for "example.com" for that Index action, and not support the other two urls. In other words, you would never link to the other forms of the URL, so their absence should never cause a problem.
We use a Nuget package called AttributeRouting to support this. When you specifiy a GET route for a page, it overrides the defaults for MVC.
Using AttributeRouting usually you'd map the index to [GET("")] but for the special case of Home where you also want to also support the root URL that omits the controller name , I think you'd also add an additional attribute with IsAbsoluteUrl:
public class HomeController : BaseController
{
[GET("")]
[GET("", IsAbsoluteUrl = true)]
public ActionResult Index()
{...
So I found a way to do it without any external Library...
In my RouteConfig I had to add these two routes at the top, just below the IgnoreRoute
routes.MapRoute(
"Root",
"Home/",
new { controller = "Redirect", action = "Home" }
);
routes.MapRoute(
"Index",
"{action}/Index",
new { controller = "Redirect", action = "Home" }
);
Then I had to create a new Controller called Redirect and I created a method for each of my other Controllers like this:
public class RedirectController : Controller
{
public ActionResult Home()
{
return RedirectPermanent("~/");
}
public ActionResult News()
{
return RedirectPermanent("~/News/");
}
public ActionResult ContactUs()
{
return RedirectPermanent("~/ContactUs/");
}
// A method for each of my Controllers
}
That's it, now my site looks legit. No more Home, no more Index in my URLs, this of course has the limitation of not being able to accept parameters to any of the Index methods of your Controllers though if it was really necessary, you should be able to tweak this to achieve what you want.
Just an FYI, if you want to pass an argument to your Index Action, then you can add a third route like this:
routes.MapRoute(
name: "ContactUs",
url: "ContactUs/{id}/{action}",
defaults: new { controller = "ContactUs", action = "Index", id = UrlParameter.Optional }
);
This will create a URL like this: /ContactUs/14

testing ASP.NET MVC controller Httpget

We just started using ASP.NET MVC3 and we want to unit test our controller.
Here is my controller function:
[HttpGet]
Public ActionResult Action()
{
Guid Id = Guid.Empty;
string[] UrlSegments = Request.Url.Segments;
Guid.TryParse(UrlSegments[UrlSegments.Count() - 1], out Id);
if(Id == Guid.Empty)
return RedirectToAction("ErrorPage");
}
I want to test this controller function.I have put the matching route to match this function in my global.asax file. Basically I am trying to retrieve the guid from the URl and if it is not good then take him to error page.
HttpRequestBase class URl is no setter,so I am confused how to test this functionality?
As for testing read the link provided in the comments above but I would recommend doing some reading on MVC Routing or here, it does exactly what you are trying to achieve.
Have a look in your global.ascx.cs file you will find something like this:
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
);
This is the out of the box route for the MVC framework.
Routes will match a url based on the convention you give them.
So based on the default route above and given a url like this:
http://localhost:portnumber/MyController/MyAction/8B4B93DE-76CA-4552-B4AA-460400761EAD
It will try and match this url to a controller called MyController with an action called MyAction, which receives and Id. It will only hit this action if all the criteria match.
If there is no id in the URL and id defined on your action method is not a nullable type then it simple wont execute. It will rather try match another Url, if it cant find one it will give a 404.
Like this:
public class MyController : Controller {
[HttpGet]
Public ActionResult MyAction(Guid id)
{
}
}

C# MVC3 - "The resource cannot be found"

I am trying to create another controller for my Ajax handler - so now I have an AppController (The site controller) and an AjaxController (the Ajax request handler).
The problem is, that when I access http://LocalHost:82/Ajax , I get The resource cannot be found. When I access http://LocalHost:82/Ajax/Index , it works.
The problem is the default routing, right? Here is my routing:
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "App", action = "NewRequests", id = UrlParameter.Optional } // Parameter defaults
);
If you need more info dont hesitate to ask. Thanks!
Your routing:
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "App", action = "NewRequests", id = UrlParameter.Optional } // Parameter defaults
);
Declares that default action is NewRequests, so it is expected that your AjaxController would have [HttpGet] NewRequests actions. You can do that by,
[HttpGet]
public ActionResult NewRequests()
{
// ...
}
or
[HttpGet, ActionName("NewRequests")]
public ActionResult WhatEverNameOfActionYouLike()
{
// ...
}
Is there an NewRequests method returning an ActionResult in the Ajax controller? If not, this makes sense as your default action is NewRequests.

Categories

Resources