How can I fix my route configuration to accept a second parameter? - c#

I've modified my Get() endpoint to take another parameter, and it doesn't work anymore
public async Task<AjaxResponse> Get(long id, string appType)
{
}
This is the route config that I've added for the new parameter (if I don't add this, the request returns a 404):
routes.MapHttpRoute(
name: "GetUser",
routeTemplate: "api/{controller}/{userId}/{appType}"
);
Now requests for that endpoint, e.g.
/api/AccountApi/343434338361295/customer
end up at the default framework generated Get() endpoint:
public IEnumerable<string> Get()
{
return new string[] { "value1", "value2" };
}
What's wrong with my routing configuration, and what can I do to fix it?
For reference, my entire route configuration is as follows:
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
//ASP.NET Web API Route Config
routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
routes.MapHttpRoute(
name: "CreateOrLogin",
routeTemplate: "api/{controller}/CreateOrLogin/{appType}/{userId}"
);
routes.MapHttpRoute(
name: "GetUser",
routeTemplate: "api/{controller}/{userId}/{appType}"
);
routes.MapHttpRoute(
name: "GetAdsForRetailer",
routeTemplate: "api/{controller}/GetAdsForRetailer/{userId}/{page}/{pageSize}"
);
routes.MapHttpRoute(
name: "GetLatestAds",
routeTemplate: "api/{controller}/GetLatestAds/{userId}/{maxId}"//
);
routes.MapHttpRoute(
name: "GetAd",
routeTemplate: "api/{controller}/GetAd/{userId}/{id}"//
);
routes.MapHttpRoute(
name: "RegisterUser",
routeTemplate: "api/{controller}/RegisterUser/"//
);
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
}

I cannot test this right now, but I think that the names you define in the route must match those in the Get method, i.e. instead of
routeTemplate: "api/{controller}/{userId}/{appType}"
you should have
routeTemplate: "api/{controller}/{id}/{appType}"
The route should match regardless of the names you give, but then the framework will probably try to use reflection to determine the method to call, and for that parameter names will be relevant.

There are two mistakes in your code:
Firstly, The name of your first parameter is not correct. Either use userId or update your route config as #paolo-tedesco said.
Apart from it, the types of parameters in Actions should always be nullable. You're supplying long for userId. Rest of your code is perfect. Just try using long? in the action.
public async Task<AjaxResponse> Get(long? userId, string appType)
{
}

Related

WebApi Routing: api/{controller}/{id} and api/{controller}/{action} at the same time

I have default webapi routing configuration:
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional },
);
I want to support following scenarios:
//api/mycontroller
public IQueryable<MyDTO> Get();
//api/mycontroller/{id} where id can be anything except "customaction1" and "customaction2"
public HttpResponseMessage Get(string id);
//api/mycontroller/customaction
[HttpPost]
public void CustomAction1([FromBody] string data);
[HttpPost]
public void CustomAction2([FromBody] string data);
I have tried to apply [Route("api/mycontroller/customaction1")] to the CustomAction1 method, and similar to CustomAction2 but getting:
Multiple actions were found that match the request:
CustomAction1 on type MyProject.WebApiService.MyController
CustomAction2 on type MyProject.WebApiService.MyController
Make sure that you configured attribute routing along with your default configuration
//....
config.MapHttpAttributeRoutes()
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional },
);
//....
If you want to do the same with out attribute routing then you will need to configure routes explicitly
//This one constrains id to be an int
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { action="Get", id = RouteParameter.Optional },
constraints : new { id = #"\d" }
);
//This one should catch the routes with actions included
config.Routes.MapHttpRoute(
name: "ActionRoutes",
routeTemplate: "api/{controller}/{action}"
);

WebAPI - No action was found on the controller

I am trying to make hierarchical link in my RESTapi. For example:
Following url will give me details of actor id 1:
/api/v1/actor/id/1/
Following url is expected to give me all movies of actor id 1:
/api/v1/actor/1/movies
My routes:
config.Routes.MapHttpRoute(
name: "DefaultCAApi",
routeTemplate: "api/v1/{controller}/{action}/{id}",
defaults: new { id = RouteParameter.Optional }
);
config.Routes.MapHttpRoute(
name: "DefaultOneLevelNested",
routeTemplate: "api/v1/{controller}/{levelOneId}/{action}",
defaults: new { id = RouteParameter.Optional }
);
My Actions in ActorController:
[HttpGet]
public HttpResponseMessage Id(int id)
{
// logic
return Request.CreateResponse(HttpStatusCode.OK, actor);
}
[HttpGet]
public HttpResponseMessage Movies(int levelOneId)
{
// logic
return Request.CreateResponse(HttpStatusCode.OK, movies);
}
But this setup is not working for me.
/api/v1/actor/id/1/ gives me proper response
But /api/v1/actor/1/movies is throwing following error:
No action was found on the controller 'Actor' that matches the name '1'."
I did follow this thread, but it did not work for me.
Can some please suggest what wrong I am doing here? I am using MVC 4, WebAPI.
Try switching the order of your routes:
config.Routes.MapHttpRoute(
name: "DefaultOneLevelNested",
routeTemplate: "api/v1/{controller}/{levelOneId}/{action}",
defaults: new { id = RouteParameter.Optional }
);
config.Routes.MapHttpRoute(
name: "DefaultCAApi",
routeTemplate: "api/v1/{controller}/{action}/{id}",
defaults: new { id = RouteParameter.Optional }
);
Order matters when creating routes. The way you have it, it's matching the first one (the default route) first, and not finding an action with the name of "1".
You might also want to look into MVC Attribute routing, I think it's a tad easier to work with: http://blogs.msdn.com/b/webdev/archive/2013/10/17/attribute-routing-in-asp-net-mvc-5.aspx
This work around did thing for me:
config.Routes.MapHttpRoute(
name: "DefaultCAApi",
routeTemplate: "api/v1/{controller}/{action}/{id}",
defaults: new { id = RouteParameter.Optional }
);
config.Routes.MapHttpRoute(
name: "LevelOneNested",
routeTemplate: "api/v1/{controller}/{id}/details/{action}",
defaults: new { id = RouteParameter.Optional }
);
Basically I have added 1 more path level to my url. It finally became:
/api/v1/actor/4/details/movies
Use these routes:
config.Routes.MapHttpRoute(
name: "DefaultOneLevelNested",
routeTemplate: "api/v1/{controller}/{id}/{action}",
constraints: new { controller = "actor", action ="movies" }
);
config.Routes.MapHttpRoute(
name: "DefaultCAApi",
routeTemplate: "api/v1/{controller}/{action}/{id}",
defaults: new { id = RouteParameter.Optional }
);
They should match your initial urls.

Web API Multiple actions were found that match the request on POST with only one action

I'm having an issue where I'm getting the error:Multiple actions were found that match the request on POST on the url /api/v1/audit
I'm confused to how this is happening since I only have one action in the controller. Does anyone know what may be going on?
public class AuditController :ApiControllerBase
{
[HttpPost]
public int Post([FromBody]string value)
{
return -1;
}
}
Routes:
routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/v1/{controller}/{id}",
defaults: new {id = RouteParameter.Optional}
);
routes.MapHttpRoute(
name: "FacetApi",
routeTemplate: "api/v1/{controller}/${action}/{id}",
defaults: new { id = RouteParameter.Optional }
);

Correctly crafting routes for asp.net web api

I am struggling to correctly design a DELETE http request in my ASP Web application.
I have the following route defined:
public const string ControllerOnly = "ApiControllerOnly";
public const string ControllerAndId = "ApiControllerAndIntegerId";
private const string ControllerAction = "ApiControllerAction";
public static void Register(HttpConfiguration config)
{
var routes = config.Routes;
// api/projects
routes.MapHttpRoute(
name: ControllerOnly,
routeTemplate: "api/{controller}"
);
//api/projects/1
routes.MapHttpRoute(
name: ControllerAndId,
routeTemplate: "api/{controller}/{id}",
defaults: null,
constraints: new { id = #"^\d+$" } // id must be all digits
);
routes.MapHttpRoute(
name: ControllerAction,
routeTemplate: "api/{controller}/{action}"
);
}
I am expecting it to hit the following action:
public HttpResponseMessage Delete(int i)
{
//content remove for brevity
return new HttpResponseMessage(HttpStatusCode.NoContent);
}
In fiddler I try to test using the following: DELETE http://localhost:port/api/controller/1
but that method never gets hit. Instead, the following method is hit:
public HttpResponseMessage Delete()
{
//content remove for brevity
return new HttpResponseMessage(HttpStatusCode.NoContent);
}
I have a basic understanding of routing but shouldn't that only route I defined ensured that the previous test is successful?
Note that I have no problem with GET and POST verbs
Any help appreciated
I guess you need to add the action part in your route as below :-
routes.MapHttpRoute(
name: ControllerAndId,
routeTemplate: "api/{controller}/{action}/{id}",
defaults: null,
constraints: new { id = #"^\d+$" } // id must be all digits);
Add/Register other route-path before default route. It takes always first prior one. So, in your case you need to register one more path in WebApiConfig as below.
routes.MapHttpRoute(
name: "WithActionApi",
routeTemplate: "api/{controller}/{action}/{Id}",
defaults: new { Id = RouteParameter.Optional
});
Note : You must register this route before your default route.
i.e, It should be as below.
public static void Register(HttpConfiguration config)
{
routes.MapHttpRoute(
name: "WithActionApi",
routeTemplate: "api/{controller}/{action}/{Id}",
defaults: new { Id = RouteParameter.Optional
});
routes.MapHttpRoute(
name: ControllerAndId,
routeTemplate: "api/{controller}/{id}",
defaults: null,
constraints: new { id = #"^\d+$" } // id must be all digits
);
}

Need to pass the URL with arguments in webapi

I have the below URLs to pass the different API.
/shared/rendererjob -- I done
/shared/rendererjob/{jobId} -- I done
/shared/rendererjob/{jobId} -- done
/shared/rendererjob/{jobId}/status -- done
/shared/renderer/documentconverter/document -- I done
/shared/renderer/documentconverter/storage -- I done
/shared/renderer/documentconverter/callback -- I done
/shared/rendererhealth?q={level} -- **I dont know how to do this one**
How to write the webconfig.cs for this -- /shared/rendererhealth?q={level}
My config code is below.
config.Routes.MapHttpRoute(
name: "RendererApi",
routeTemplate: "shared/{controller}/{renderGUID}",
defaults: new { action = "rendererJob", renderGUID =
RouteParameter.Optional }
);
config.Routes.MapHttpRoute(
name: "RendererAPiStatus",
routeTemplate: "shared/{controller}/{jobid}/status",
defaults: new { action = "getJobStatus", jobid = RouteParameter.Optional }
);
config.Routes.MapHttpRoute(
name: "DocumentConverterApi",
routeTemplate: "shared/renderer/{controller}/{action}"
);
The above code is working for what I have done.
Please let me know how to config the controler with arguments.
**How to achieve this path --
http://localhost:12345/shared/rendererhealth?q={level}**
As your routes appear to be very controller dependent, the first thing I would do is change your existing routing as follows:
config.Routes.MapHttpRoute(
name: "RendererApi",
routeTemplate: "shared/rendererjob/{renderGUID}",
defaults: new { action = "rendererJob",
renderGUID = RouteParameter.Optional,
controller="rendererJob" }
);
config.Routes.MapHttpRoute(
name: "RendererAPiStatus",
routeTemplate: "shared/rendererjob/{jobid}/status",
defaults: new { action = "getJobStatus",
controller="rendererjob" }
);
config.Routes.MapHttpRoute(
name: "DocumentConverterApi",
routeTemplate: "shared/renderer/documentconverter/{action}",
defaults: new { controller="documentconverter" }
);
Note you cannot have an optional parameter in the middle of a route so I have changed your RendererAPiStatus route so that jobid is mandatory.
Next add a new route at the end for your new resource:
config.Routes.MapHttpRoute(
name: "RendererHealthApi",
routeTemplate: "shared/rendererhealth",
defaults: new { controller="rendererhealth" }
);
You can then add your new controller method:
public class RendererHealthController : ApiController
{
public string Get(int q)
{
return "hello";
}
}
Note the above assumes you are using a GET request and {level} is an integer.

Categories