Giving more than one maproutes in Webapicontroller - asp.net

I have two methods in my Web API controller as follows:
public samplecontroller: webapicontroller
{
[HttpPost]
public void PostMethod()
[HttpGet]
public void GetValues(int a,int b)
}
I have the following in global.asax:
routes.MapHttpRoute
("Default API Route", "api/{controller}/{id1}/{id2}/{id3}/{id4}/{id5}",
new { id1 = UrlParameter.Optional, id2 = UrlParameter.Optional, id3 = UrlParameter.Optional, id4 = UrlParameter.Optional, id5 = UrlParameter.Optional });
If I want to call the second method i.e., GetValues(int a,int b), can I write one more HttpRoute in Global.asax as follows?
routes.MapHttpRoute(
name: "ActionApi",
routeTemplate: "api/{Sample}/{GetValues}/{a}/{b}",
defaults: new { a = UrlParameter.Optional, b=UrlParameter.Optional }
);
So can I create more than one maproute in global.asax?
And, to provide the optional parameter, should I give the same as parameters like a and b only?

You can have multiple routes in global.asax; each incoming request will go to the first route that matches. That means that the more specific ones should go first. A URL matches a route if:
the controller and action route values are defined.
All required route values (both ones in the curly brackets in the route, as well as non-nullable parameters in the Action) are defined.
That said, your proposed route api/{Sample}/{GetValues}/{a}/{b} doesn't make sense. It creates two new (meaningless) route values Sample and GetValues, and doesn't provide a definition controller or action. I think what you meant to write is this:
routeTemplate: "api/Sample/GetValues/{a}/{b}",
defaults: new { controller: "Sample", action: "GetValues", a = UrlParameter.Optional ,b=UrlParameter.Optional }
This will match the URI /api/Sample/GetValues/1/2 to your action.
routeTemplate: "api/Sample/GetValues/{a}/{b}",
defaults: new { controller: "Sample", action: "GetValues", a = UrlParameter.Optional ,b=UrlParameter.Optional }

Related

How does RedirectToRoute work and how to pass data in it?

I'm trying to redirect to a route that is in the RecomController and the action is Index, i have defined the path in my RouteConfig file and have also specified an id parameter that i pass when i call my RedirectToRoute function. For some reason it can't find that path.
I have also created a Route attribute above the RecomController Index action but it still doesn't navigate me to that path. Am i missing something?
RouteConfig.cs:
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
routes.MapRoute(
name: "Recomroute",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Recom", action = "Index", id = UrlParameter.Optional }
);
}
RecomController.cs:
[Route("Recom/Index")]
public ActionResult Index(int id)
{
............//Functioning
}
Calling the function (IN ANOTHER CONTROLLER):
ProjectController.cs:
return RedirectToRoute("Recom/Index/{id}", new {id = projectdto.Id });
Sounds like you're using wrong route name or path in RedirectToRoute(), hence it doesn't work:
// this is wrong because first parameter did not match
return RedirectToRoute("Recom/Index/{id}", new {id = projectdto.Id });
For two parameters overload, it requires route name (not route path) and route values, as shown in definition below:
protected internal RedirectToRouteResult RedirectToRoute(string routeName,
RouteValueDictionary routeValues)
Hence, you need to provide complete route name and route values defined in RegisterRoutes (e.g. Recomroute).
return RedirectToRoute("Recomroute", new {
controller = "Recom",
action = "Index",
id = projectdto.Id
});
Side notes:
1) You still need to provide controller, action and id parameters in order to match route definition.
2) The Recomroute seem defined below default route with same route segments definition which overrides all custom routes beneath it, if you want to evaluate Recomroute first move it to the top order and use different path against default route.

ASP.NET routes not triggering as I expect

trying to get started with ASP.NET MVC.
I encountered a few difficulties while setting up basic routes.
My routes are as follows:
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
routes.MapRoute(
name: "ImproItem",
url: "{controller}/{action}/{type}",
defaults: new { controller = "ImproItemForm", action = "Index", type = UrlParameter.Optional }
);
}
My view calls :
<li>#Html.ActionLink("linkLabel", "Index", "ImproItemForm", new { type = "blablabla" }, null)</li>
My controller action sig is:
public class ImproItemFormController : Controller
{
...
public ActionResult Index(String t)
{
...}
}
The view generates the following HTML:
<li>linkLabel</li>
This looks OK to me.
However, this link correctly calls the controller's action (using ImproItem route) but it does not pass the blablabla argument. The parameter t = null when I debug the app.
Can you explain me why?
What should I change to correctly receive the blablabla argument?
Now if I start the application and try to browse
Also is it normal that when I browse:
http://localhost:55193/ImproItemForm/Index?id=foobar
It does call the ImproItemFormController.Index(String t) method ?
I did not expect that this URL would match with this route:
routes.MapRoute(
name: "ImproItem",
url: "{controller}/{action}/{type}",
defaults: new { controller = "ImproItemForm", action = "Index", type = UrlParameter.Optional }
);
I thought the argument needs to have the same name than in the route : type and not id.
Thx in advance for your help.
I thought the argument needs to have the same name than in the route :
type and not id.
Actually when you request the URL - http://localhost:55193/ImproItemForm/Index?id=foobar, it actually calls the Default route only, and not the custom route that you have created. Default route has - controller name, action name and id. That means, if there is any URL matching this pattern (i.e., {controllername}/{actionname}/{id}) would match the default route.
Order of routes are very important in route collection because route table is built top-to-bottom, so as soon as the URL finds its first matching route, it stops scanning further.So ideally, default route should be the bottom most route in route collection.
I guess all your problems for this particular scenario should be resolved by performing following two steps-
Move default route to the bottom in route collection in RouteConfig.cs
Rename parameter "t" to "type" in Index action.
Change the name of the parameter in your action to match the name in the ActionLink
public ActionResult Index(String type)

MVC action results in 404 with "No type was found that matches the controller" invoking default action on controller works

I inherited some ASP.Net MVC code and am tasked with adding some new features. I am a complete beginner using ASP.Net MVC and come from a background of mainly using Web Forms.
I added a new controller (ApiController) and I added the following actions to it:
// GET: /Api/Index
public string Index()
{
return "API Methods";
}
// GET: /Api/DetectionActivity
public JsonResult DetectionActivity()
{
var detections = from d in db.Detections
orderby DbFunctions.TruncateTime(d.CreationTime)
group d by DbFunctions.TruncateTime(d.CreationTime) into g
select new { date = g.Key, count = g.Count() };
ViewBag.DetectionCounts = detections.ToList();
return Json(detections, JsonRequestBehavior.AllowGet);
}
My RouteConfig.cs has the following registered routes.
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Dashboard", action = "Index", id = UrlParameter.Optional }
);
This looks like the tutorials I've been reading but it's not working and I'm probably missing something.
If I go to localhost:21574/api I see the output from the Index() action, "API Methods".
If I go to localhost:21574/api/DetectionActivity it throws a 404 with the following data in the response:
{
"Message":"No HTTP resource was found that matches the request URI 'http://localhost:21574/Api/DetectionActivity'.",
"MessageDetail":"No type was found that matches the controller named 'DetectionActivity'."
}
I'm thinking there is something I need to do that I'm not.
Any suggestions on what to do next?
Update 1
I tried this with my RouteConfig.cs
routes.MapRoute(name: "ApiController",
url: "{controller}/{action}"
);
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Dashboard", action = "Index", id = UrlParameter.Optional }
);
These were my results:
If I go to localhost:21574/api I see the output from the Index() action, "API Methods". Same as before.
If I go to localhost:21574/api/DetectionActivity it throws a 404 with the following data in the response:
{
"Message":"No HTTP resource was found that matches the request URI 'http://localhost:21574/Api/DetectionActivity'.",
"MessageDetail":"No type was found that matches the controller named 'DetectionActivity'."
}
Same as before.
If I go to localhost:21574/Api/Api/DetectionActivity it throws a 404 with this data in the response:
{
"Message":"No HTTP resource was found that matches the request URI 'http://localhost:21574/Api/Api/DetectionActivity'.",
"MessageDetail":"No type was found that matches the controller named 'Api'."
}
Now it's saying it can't find a controller named "Api".
from your Route Config
the URL should be: localhost:21574/Api/Dashboard/DetectionActivity
or if you really need localhost:21574/Api/DetectionActivity (not recommended)
change your Register method in WebApiConfig class to
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{action}/{id}",
defaults: new { controller = "Dashboard", action = "Index", id = RouteParameter.Optional }
);

Url.Action does not use desired route for output

I have the following route definitions in my MVC3 website:
routes.MapRoute(
"FB", // Route name
"fb/{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = UrlParameter.Optional } // Parameter defaults
).RouteHandler = new RH();
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = UrlParameter.Optional } // Parameter defaults
);
My custom "RH" handler's code is
public class RH : MvcRouteHandler
{
protected override IHttpHandler GetHttpHandler(RequestContext requestContext)
{
//here I store somewhere that 'fb' prefix is used, so logic is different in some places
return base.GetHttpHandler(requestContext);
}
}
What I want to achieve, that when my website is accessed with the 'fb' subpath-prefix, then my website-logic executes a little bit different way.
The problem is, that when I access my site normally (eg. http://localhost), then when I execute
Url.Action('action' 'controller')
, then the output is "http://localhost/fb/controller/action".
I want to achieve, that when my site was accessed with 'fb' prefixed subpath, then my Url.Action calls output /fb/controller/action path, and if I access the website normally (without 'fb' prefix subpath), then Url.Action calls output /controller/action
The main thing, that /fb/controller/actions have to route to the same controllers/actions as when the site is accessed via /controller/action format.
The 'fb' route is just needed to store some temporary info when 'fb' prefix i used.
Seems I found a solution based on this link (MVC 3 Routing and Action Links not following expected contextual Route), new path-placeholder introduced and constraint added.
Maybe it's not good enough, or you know better than this, but seems to work for me:
routes.MapRoute(
"FB", // Route name
"{path}/{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = UrlParameter.Optional }, // Parameter defaults
new { path = "fb" }
).RouteHandler = new RH();
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = UrlParameter.Optional } // Parameter defaults
);

Switching to {controller}/{id}/{action} breaks RedirectToAction

I am trying to use proper REST urls with MVC. To do that I switched default Routing from:
{controller}/{action}/{id}
to
{controller}/{id}/{action}
so instead of:
/Customer/Approve/23
there is now
/Customer/23/Approve
ActionLink seems to work ok, but the following code in CustomerController:
[CustomAuthorize]
[HttpGet]
public ActionResult Approve(int id)
{
_customerService.Approve(id);
return RedirectToAction("Search"); //Goes to bad url
}
ends up on url /Customer/23/Search. While it should be going to /Customer/Search. Somehow it remembers 23 (id).
Here is my routing code in global.cs
routes.MapRoute(
"AdminRoute", // Route name
"{controller}/{id}/{action}",
new { controller = "Home", action = "Index", id = UrlParameter.Optional },
new { id = new IsIntegerConstraint() }
);
routes.MapRoute(
"Default",
"{controller}/{action}",
new { controller = "Home", action = "Index" });
If I switch the two functions, RedirectToAction starts working, but using:
Html.ActionLink("Approve", "Approve", new { Id = 23})
Now generates /Customer/Approve?id=23, instead of /Customer/23/Approve.
I could specify direct urls like ~/Customer/23/Approve, instead of using ActionLink and RedirectToAction, but would rather stick to functions provided by MVC.
When you use RedirectToAction(), internally, MVC will take the existing route data (including the Id value) to build the url. Even if you pass a null RouteValueDictionary, the existing route data will be merged with the new empty route value data.
The only way around this I can see is to use RedirectToRoute(), as follows:
return RedirectToRoute("Default", new { controller = "Customer", action = "Search"});
counsellorben
Try passing in new (empty) RouteValueDictionary in your controller
return RedirectToAction("Search", new System.Web.Routing.RouteValueDictionary{});
And here:
Html.ActionLink("Approve", "Approve", new { Id = 23})
I don't even know how can it pick up the Customer controller, since you are not specifying it anywhere. Try providing both controller and action to ActionLink helper.
Try passing the current route data to methon in your controller action:
return RedirectToAction("Search", this.RouteData.Values);
Remove this part:
id = UrlParameter.Optional
may be resolve the problem; when you define "id" as an optional parameter, and you have the "Default" map, the "Default" and the "AdminRoute" are same together!
regards.
I was having a similar problem. Route values that were passed to my controller action were being reused when I tried to redirect the user with RedirectToAction, even if I didn't specify them in the new RouteValueDictionary. The solution that I came up with (after reading
counsellorben's post) with was to clear out the RouteData for the current request. That way, I could stop MVC from merging route values that I didn't specify.
So, in your situation maybe you could do something like this:
[CustomAuthorize]
[HttpGet]
public ActionResult Approve(int id)
{
_customerService.Approve(id);
this.RouteData.Values.Clear(); //clear out current route values
return RedirectToAction("Search"); //Goes to bad url
}
I had a similar problem and was able to solve it by adding the id to the default route as well.
routes.MapRoute(
"Default",
"{controller}/{action}/{id}",
new { controller = "Home", action = "Index", id = UrlParameter.Optional });
If there is truly no id in your default route then you could also try:
routes.MapRoute(
"Default",
"{controller}/{action}",
new { controller = "Home", action = "Index", id = string.Empty });

Resources