ASP.NET MVC2 Routing Issue - asp.net-mvc-2

i have two controllers with the same name in different sub folder
My Controllers looks like
Controllers
api
UserController
help
UserController
I want to access my first controller when the user requests http://mysite/api/User/Index
and access my second controller when the user requests http://mysite/help/User/Index
how to configure routing in Global.asax and how the views folders will look like?
will it look like?
Views
User
api
Index
help
Index
Thanks and Regards.

You could use namespace constraints:
routes.MapRoute(
"help",
"help/{controller}/{action}",
new { controller = "User", action = "Index" },
new[] { "MvcApplication1.Controllers.help" }
);
routes.MapRoute(
"api",
"api/{controller}/{action}",
new { controller = "User", action = "Index" },
new[] { "MvcApplication1.Controllers.api" }
);
As far as having sub-folders for your Views is concerned, this is not supported out of the box. You will have to write a custom view engine for this to work.
By the way have you considered using Areas? They seem like better fit for your scenario. So you would define 2 areas: help and api and have the UserController defined in both.

Related

MVC 5 - Redirect to a controller from anywhere

I am developing a MVC 5 internet application, and I wish to redirect to a controller/action result from anywhere in my application.
The controller name is "Manager", and the action result is "TestAction"
In an action result, the following code can be used:
RedirectToAction("TestAction", "Manager")
I have also coded a filter attribute as follows:
filterContext.Result = new RedirectToRouteResult( new RouteValueDictionary{{ "controller", "Manage" }, { "action", "TestAction" } });
Is there a generic way to send the user to a specific controller, action result from anywhere in a MVC application? I specifically wish to do this in an extension method.
Thanks in advance.
You can do it by simply Response.Redirect (taking the domain path and append the url).
Did you try the answer like this one https://stackoverflow.com/a/18126733/713789
In your controller you can use RedirectToAction("TestAction", "Manager") to redirect and in your view you can write windows.location.href("Manager","TestAction").
What i've done in such cases:
Dictionary<string, object> dictionary = new Dictionary<string, object>();
//
//...add parameters...
dictionary.Add("controller", "ControllerName");//ex: Home for HomeController
dictionary.Add("action", "MyMethod");
return RedirectToRoute("Default", dictionary);//"Default" is the name of the rout you're using

ASP.NET Web Api Routing Customization

I have WebApi controllers that end with the "Api" suffix in their names (For ex: StudentsApiController, InstructorsApiController). I do this to easily differentiate my MVC controllers from WebApi controllers. I want my WebApi routes to look similar to
http://localhost:50009/api/students/5 and not http://localhost:50009/api/studentsapi/5.
Currently to achieve this, I am setting up routes like
routes.MapHttpRoute(
name: "GetStudents",
routeTemplate: "api/students/{id}",
defaults: new { controller = "StudentsApi", id = RouteParameter.Optional });
routes.MapHttpRoute(
name: "GetInstructors",
routeTemplate: "api/instructors/{id}",
defaults: new { controller = "InstructorsApi", id = RouteParameter.Optional });
This is turning out to be very cumbersome as I have to add a route for each method in my controllers. I am hoping there should be an easy way to setup route templates that automatically adds the "api" suffix the controller name while processing routes.
Following #Youssef Moussaoui's direction I ended up writing the following code that solved the problem.
public class ApiControllerSelector : DefaultHttpControllerSelector
{
public ApiControllerSelector(HttpConfiguration configuration)
: base(configuration)
{
}
public override string GetControllerName(HttpRequestMessage request)
{
if (request == null)
throw new ArgumentNullException("request");
IHttpRouteData routeData = request.GetRouteData();
if (routeData == null)
return null;
// Look up controller in route data
object controllerName;
routeData.Values.TryGetValue("controller", out controllerName);
if (controllerName != null)
controllerName += "api";
return (string)controllerName;
}
}
And register it in Global.asax as
GlobalConfiguration.Configuration.Services.Replace(typeof(IHttpControllerSelector),
new ApiControllerSelector(GlobalConfiguration.Configuration));
Now that ASP.NET Web API 2 is out, there is a much less cumbersome way to do more complex routing like that you suggested, by using attribute routing.
At the top of your controller just add the following attribute:
[RoutePrefix("api/students")]
public class StudentsApiController : ApiController
{
...
}
And then before each API method:
[Route("{id}"]
public HttpResponseMessage Get(int id)
{
...
}
There is a bit of setup required, but the positives of doing routing this way are many. For one, you can put the routing with the controllers and methods that do the actual work, so you're never searching around wondering if you have the right route. Secondly and more importantly, it's much easier to do more complex routing, like having the controller name different from the route name (like you want) or having very complex patterns to match against.
I think the extensibility point you're looking for is the controller selector. You can create a class that derives from DefaultHttpControllerSelector and overrides the GetControllerName to strip out the "api" part. You can then register this controller selector on your service's configuration Services.
Following Youssef's comment on muruug's answer would look something like this
public class ApiControllerSelector : DefaultHttpControllerSelector
{
public ApiControllerSelector (HttpConfiguration configuration) : base(configuration) { }
public override string GetControllerName(HttpRequestMessage request)
{
return base.GetControllerName(request) + "api";
}
}

Return PartialView in MVC3 Area is not searching in area

I am working on an ASP.Net MVC 3 RC project. I have one area named Drivers. I have a LoadPartial() action in a controller in the Drivers area that returns a PartialView(string, object); When this is returned I get an error on my webpage that says "The partial view 'PublicAttendanceCode' was not found." It searched the following locations:
~/Views/AttendanceEvent/PublicAttendanceCode.aspx
~/Views/AttendanceEvent/PublicAttendanceCode.ascx
~/Views/Shared/PublicAttendanceCode.aspx
~/Views/Shared/PublicAttendanceCode.ascx
~/Views/AttendanceEvent/PublicAttendanceCode.cshtml
~/Views/AttendanceEvent/PublicAttendanceCode.vbhtml
~/Views/Shared/PublicAttendanceCode.cshtml
~/Views/Shared/PublicAttendanceCode.vbhtml
Why is it not searching in the Drivers Area?
I have the following pretty basic routes in Global.asax.cs:
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
}
);
}
And in DriversAreaRegistration.cs
public override void RegisterArea(AreaRegistrationContext context)
{
context.MapRoute(
"Drivers_default",
"Drivers/{controller}/{action}/{id}",
new { action = "RequestLeave", id = UrlParameter.Optional }
);
}
What am I missing that will make it look in the drivers area for the partial?
How are you providing area name to PartialView() method? I think you should be passing it in new { area = "Drivers" } as routeValues parameter.
The way that the MVC view engines know the area that they should look in is based on the route that was used to process the request.
In the case of the controller action that you have, are you certain that the request was processed by the area's route definition, or is it possible that the request was processed by the more general route that you defined in global.asax?
There are only four overloads of the method PartialView and it seems like neither of them accept routeValues as a parameter.
I solved this problem like this:
return PartialView(
VirtualPathUtility.ToAbsolute("~/Areas/MyArea/Views/Shared/MyView.cshtml"));
It works, but looks ugly.
This works too:
return PartialView("~/Areas/Admin/Views/Shared/MyView.cshtml", model);

MapRoute (Asp.Net MVC 2.0 .NET 4.0)

is there any possibility to create a maproute which would use always one method and it won't be necessary to put it in address?
I mean I've got controller with one method (Index) and it displays items depend on methods argument.
public ActionResult Index(string TabName)
{
var tab = (from t in BlogDB.Tabs
where t.TabName == TabName
select t).SingleOrDefault();
ViewData.Model =(Tab)tab;
return View();
}
and what I want is that I can display items putting address "www.example.com/Tabs/TabName" without "/Index/" between Tabs and TabName. I've tried:
routes.MapRoute(
"Tabs1",
"Tabs/{TabName}",
new { controller = "Tabs", action = "Index", TabName = UrlParameter.Optional }
);
But it doesn't work.
do you still have the default route? and if yes is it defined before this one?
Your problem is that asp.net mvc is trying to find the Tabs controller and the Tabname action.
Put this route before the default {controller}/{action} route

Action not found in Route table?

Just started my first MVC 2.0 .net application. And I set up some default pages like:
/Loa/Register
/Loa/About
But when I request for /Loa/sdfqsdf (random string) I get the "The resource cannot be found." error, how can I redirect this non-existing action to a default action?
Like an "action not found" default action?
thx!
Using routes
You can define more than one route (which is also quite common in real-life MVC applications), because some routes have particular settings that differ from the default one. And especially if you want to do decent SEO.
routes.MapRoute(
"DefaultRoute",
"{controller}/{action}/{id}",
new { controller = "Home", action = "Index", id = string.Empty },
new { action = "Register|Index|About" } // route constraint that limits the actions that can be used with this route
);
routes.MapRoute(
"InvalidRoutes"
"{*dummy}",
new { controller = "Home", action = "Nonexisting" }
);
If you'll add additional routes to our route table, just make sure the InvalidRoutes is defined as the last one.