ASP.NET Web API Routing in ApiController - asp.net-mvc

I've been struggling with my routing for some time now and after a few days of trying to Google the solution without luck, I'm hoping someone may be able to shine some light on my problem.
I have the following routes in my WebApiConfig:
config.Routes.MapHttpRoute(
name: "AccountStuffId",
routeTemplate: "api/Account/{action}/{Id}",
defaults: new { controller = "Account", Id = RouteParameter.Optional }
);
config.Routes.MapHttpRoute(
name: "AccountStuffAlias",
routeTemplate: "api/Account/{action}/{Alias}",
defaults: new { controller = "Account", Alias = RouteParameter.Optional }
);
and the following controller methods:
[HttpGet]
public Account GetAccountById(string Id)
{
return null;
}
[HttpGet]
public Account GetAccountByAlias(string alias)
{
return null;
}
If I call:
/API/Account/GetAccountById/stuff then it properly calls GetAccountById.
But if I call /API/Account/GetAccountByAlias/stuff then nothing happens.
Clearly order matters here because if I switch my declarations of my routes in my WebApiConfig, then /API/Account/GetAccountByAlias/stuff properly calls GetAccountByAlias, and /API/Account/GetAccountById/stuff does nothing.
The two [HttpGet] decorations are part of what I found on Google, but they don't seem to resolve the issue.
Any thoughts? Am I doing anything obviously wrong?
Edit:
When the route fails, the page displays the following:
<Error>
<Message>
No HTTP resource was found that matches the request URI 'http://localhost:6221/API/Account/GetAccountByAlias/stuff'.
</Message>
<MessageDetail>
No action was found on the controller 'Account' that matches the request.
</MessageDetail>
</Error>

You should be able to just have the following route:
config.Routes.MapHttpRoute(
name: "AccountStuffId",
routeTemplate: "api/Account/{action}/{Id}",
defaults: new { controller = "Account", Id = RouteParameter.Optional }
);
and do the following for your actions:
[HttpGet]
public Account GetAccountById(string Id)
{
return null;
}
[HttpGet]
public Account GetAccountByAlias([FromUri(Name="id")]string alias)
{
return null;
}

Is there a reason you need to be declaring two different routes?
Look at the guide at: http://www.asp.net/web-api/overview/web-api-routing-and-actions/routing-in-aspnet-web-api
They have one default route and going by the example all you need in your config is
routes.MapHttpRoute(
name: "API Default",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);

Related

Why do I get "No HTTP resource was found that matches the request URI" and "No action was found on the controller " errors

I know similar questions have been asked, and answered, before but none of them seems to fix my errors...
I have a Controller with the following:
[RoutePrefix("api/Parts")]
public class PartsController : ApiControllerBase
{
[HttpDelete]
[Route("{id:long}")]
[ActionName("Delete")]
[ResponseType(typeof(ServerResponse))]
public IHttpActionResult Delete(long id)
{...
}
}
and a routes set up thus in WebApiConfig:
config.Routes.MapHttpRoute(
name: "DeleteSOR",
routeTemplate: "api/SORs/{id:long}",
defaults: new { controller = "Parts", action = "Delete" }
);
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
calling from Postman, the following URI works:
http://localhost:48818/api/Parts/0
but the following URI:
http://localhost:48818/api/SORs/0
returns 2 errors:
No HTTP resource was found that matches the request URI 'http://localhost:48818/api/SORs/0'
No action was found on the controller 'Parts' that matches the name 'Delete'
I'm sure I've done something minor/silly, but what please?

Conflicts with routing when using default {controller}/{id} route and {controller}/{action}/{id} route

I have the following routes setup;
RouteTable.Routes.MapHttpRoute(
name: "ActionApi",
routeTemplate: "api/{controller}/{action}/{id}",
defaults: new { id = RouteParameter.Optional });
RouteTable.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = System.Web.Http.RouteParameter.Optional },
constraints: null,
handler: new WebApiMessageHandler(GlobalConfiguration.Configuration));
and the following controller setup;
public class GetFileController : ApiController
{
[HttpGet]
public HttpResponseMessage Get(string id)
{
return Request.CreateResponse(HttpStatusCode.OK);
}
}
The issue I have here is that this url
/api/GetFile/id_is_a_string
returns this error;
<Error>
<Message>
No HTTP resource was found that matches the request URI /api/GetFile/id_is_a_string.
</Message>
<MessageDetail>
No action was found on the controller 'GetFile' that matches the name 'id_is_a_string'.
</MessageDetail>
</Error>
Is there any way to get around having it not think the string parameter is actually the action name?
I know I could change my request URL to be;
/api/GetFile?id=id_is_a_string
but this routing change affects a lot of other controllers I already have set and don't really wish to go through everything to switch it up to send the request this way.
If I re-order the routes, it seems to work as it did but for my new controller which I would've ideally liked to have multiple endpoints within, I get this error;
ExceptionMessage=Multiple actions were found that match the request:
New Controller
public class GettingThingsController : ApiController
{
[HttpPost]
public IHttpActionResult GetPeople()
{
return Ok();
}
[HttpPost]
public IHttpActionResult GetProducts()
{
return Ok();
}
}
Is there anyway of achieving what I need at all?!
You can try to specify parameters with Regex:
routeTemplate: "api/{controller}/{action:regex([a-z]{1}[a-z0-9_]+)}/{id:regex([0-9]+)}",
routeTemplate: "api/{controller}/{id:regex([0-9]+)}",
These regex works in Route attribute. You can test it in RouteTable mappings.

Dealing with multiple GET actions Web API

I am new to WEB API and trying to set up routing for multiple GET actions.
Controller Code
// Get api/values
public IEnumerable<tblUser> Get()
{
//whatever
}
// Get api/values/action
[ActionName("GetByQue")]
public IEnumerable<tblQue> GetQue()
{
//whatever
}
// Get api/values/action
[ActionName("GetUserScore")]
public IEnumerable<tblScore> GetScore(string user)
{
//whatever
}
Config
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional}
);
config.Routes.MapHttpRoute(
name: "DefaultActionApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { action = "GetByQue" }
);
config.Routes.MapHttpRoute(
name: "DefaultStringApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { action = "GetUserScore" }
);
When I try with http://localhost:54118/api/remote/GetByQue URL getting this error
{
"Message": "The request is invalid.",
"MessageDetail": "The parameters dictionary contains a null entry for parameter 'id' of non-nullable type 'System.Int32' for method 'System.String Get(Int32)' in 'HydTechiesApi.Controllers.HydTechiesApiController'. An optional parameter must be a reference type, a nullable type, or be declared as an optional parameter."
}
is my routing wrong? Any help would be valuable as I am not able to find a solution.
You should add {action} to routeTemplate instead of {id} in the second configuration
config.Routes.MapHttpRoute(
name: "DefaultActionApi",
routeTemplate: "api/{controller}/{action}",
defaults: new { action = "GetByQue" }
);
also you can try to use route attribure on action :
[ActionName("GetByQue")]
[Route("api/remote/GetByQue")]
public IEnumerable<tblQue> GetQue()
{
//whatever
}
or change order(the second configuration and first configuration) of configuration in WebApiConfig.cs
You made a couple of mistakes in your route. As your example code below:
config.Routes.MapHttpRoute(
name: "DefaultActionApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { action = "GetByQue" });
//url: http://localhost:54118/api/remote/GetByQue
(1). routeTemplate: "api/{controller}/{id}". you specify your route has an id and it is not Optional. So your URL must have id. That's what your error showed.you can handle with the issue like below:
defaults: new { id = RouteParameter.Optional }
(2). defaults: new { action = "GetByQue" }); you did not say any thing about action in your routeTemplate. your defaults about action, which does not have any meaning.
(3). From your route, your URL should look like http://localhost:54118/api/remote/5 , you should not get mutiple get method by your route.
There are some solutions, which you may use:
(1). change route like below:
config.Routes.MapHttpRoute(
name: "DefaultActionApi",
routeTemplate: "api/{controller}/{action}/{id}",
defaults: new { id = RouteParameter.Optional }
);
please add [HttpGet] in each method just in cause.
[HttpGet]
public IEnumerable<tblUser> Get()
{......}
[HttpGet]
[ActionName("GetByQue")]
public IEnumerable<tblQue> GetQue()
{......}
[HttpGet]
[ActionName("GetUserScore")]
public IEnumerable<tblScore> GetScore(string user)
{......}
Now you can use URL like http://localhost:54118/api/remote/GetByQue
Very Useful Tips: Using [Route("")] tag to specify parameters
**You also have to change Route like above (1)
in Controller, please specify request method to make sure the get method
[HttpGet]
[ActionName("GetUserScore")]
[Route("api/remote/GetScore/{user}")]
public IEnumerable<tblScore> GetScore(string user)
{.....}
//URL: http://localhost:54118/api/remote/GetScore/user

How do I set default Action for Controller?

So I have 2 controller:
[AllowCrossSiteJson]
public class ItemController : ApiController {
[HttpGet]
public LinkedList<Object> FindItem([FromUri]ItemQuery query) {
....
}
}
And
[AllowCrossSiteJson]
public class SubDepController : ApiController
{
[HttpGet]
public LinkedList<Object> FindSubDep(string ID) {
....
}
}
Here is the thing, I try to call both:
http://localhost:43751/api/SubDep
http://localhost:43751/api/Item
And the Item Controller works but the SubDep does not work! Why is that?
Here is my WebApiConfig:
public static void Register(HttpConfiguration config) {
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
config.Routes.MapHttpRoute(
name: "withAction",
routeTemplate: "api/{controller}/{action}/{id}",
defaults: new { id = RouteParameter.Optional }
);
}
The error I get back is this:
{"Message":"No HTTP resource was found that matches the request URI 'http://localhost:43751/api/SubDep'.","MessageDetail":"No action was found on the controller 'SubDep' that matches the request."}
BONUS question:
How does ASP.NET MVC know that I try to hit:
http://localhost:43751/api/Item
It automatically go to the FindItem Action? It's like pure MAGIC to me!!
When you try to call FindSubDep action, your query string should be like belwo:
http://localhost:43751/api/SubDep/1
For the bonus question. It gets to the correct action because of the HTTP verb [GET] in your case, when you make a GET request for
http://localhost:43751/api/Item
it will find an action with [HttpGet] attribute on Item controller.

Adding Routes for WebAPI in MVC 4

I've got a WebApi Controller and want to add a route.
Here is my Controller ...
public class ExtraInformationController : ApiController
{
private readonly ExtraInformationRepository _extraInfoRepository = new ExtraInformationRepository();
public ExtraInformation Get(int assetId)
{
return _extraInfoRepository.GetByAssetID(assetId).FirstOrDefault();
}
}
Heres my route ...
routes.MapHttpRoute(
"ExtraInformation",
"api/ExtraInformation/{assetId}",
new { controller = "ExtraInformation", action = "Get" }
);
I want to be able to call ...
api/ExtraInformation/4
But I'm getting ...
No HTTP resource was found that matches the request URI 'http://localhost:35188/api/ExtraInformation/4'.No action was found on the controller 'ExtraInformation' that matches the request.
Can anyone assist please?
Using the generic default route should be enough looking at your example. I would swap it for this and give it a try.
routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);

Resources