Asp.NET Web Api Routing - asp.net-web-api

I have the following code in my WebApiConfig.cs
config.Routes.MapHttpRoute(
name: "Action",
routeTemplate: "api/{controller}/{action}/{id}",
defaults: new { id = RouteParameter.Optional }
);
ABCController.cs
public class ABCController : ApiController
{
[AcceptVerbs("GET")]
[ActionName("GetABCByXYZById")]
public string GetABCByXYZById(int xYZId)
{
return "GetABCByXYZById";
}
}
When I try to call the API it says not able to find the action in the controller.
/api/ABC/GetABCByXYZById/12

It's because your routeTemplate uses the name {id} for the action parameter but your action actually takes in a parameter with name xYZId.
Try changing your action parameter to called id and it should work:
public string GetABCByXYZById(int id)

Related

ASP.NET Web Api 2 routing issue

I really can't understand why it does not work. I have the following code:
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
config.MapHttpAttributeRoutes();
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
}
}
[RoutePrefix("api/Profile")]
[System.Web.Http.AuthorizeAttribute]
[IdentityBasicAuthenticationAttribute]
public class ProfileApiController : ApiController
{
[HttpPost]
[ValidateApiContentLength]
[ValidateApiMimeMultipart]
[Route("Upload")]
public async Task<HttpResponseMessage> UploadDocumentAsync(string description)
{
//....
}
}
}
but when I call: http://localhost:11015/api/profile/Upload
I get 404 error:
{
"Message": "No HTTP resource was found that matches the request URI 'http://localhost:11015/api/profile/Upload'.",
"MessageDetail": "No action was found on the controller 'ProfileApi' that matches the request."
}
but insight says about error:
what is incorrect?
WebApi routing can't find your UploadDocumentAsync method. In your application you're using both the routing table (in the WebApiConfig class) and attribute routing. You don't need the latter.
You can leave the routing table in the WebApiConfig class as is and drop the Route and RoutePrefix attributes.
Change your action UploadDocumentAsync in the Profile controller to:
...
[HttpPost]
public async Task<HttpResponseMessage> UploadUploadDocumentAsync(string description)
{
...
just leaving the HttpPost attribute.
You can reach your your resource by calling (you can do it via Fiddler, for exampe):
POST http://localhost:11015/api/profile/
UPDATE:
Or if you would really like to have the "upload" part in your url, you can utilize the Route attribute for the action:
[Route("api/profile/upload")]
I have found a solution. Problem was not in the routing. Problem was in parameter of action. It should not be there for POST method. Other things leave as is
[HttpPost]
[ValidateApiContentLength]
[ValidateApiMimeMultipart]
[Route("upload")]
public async Task<HttpResponseMessage> UploadDocumentAsync()
{

Configuring Web API Route Config

I have an api action in my controller like below.
[RoutePrefix("api/export")]
public class ExportController : ApiController
{
[HttpPost]
public HttpResponseMessage Report([FromBody]ReportInput input, string reportType)
{
}
}
And I have added an configuration to my route config like this.
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{action}/{reportType}",
defaults : new {reportType = RouteParameter.Optional}
);
But I cannot call my API url below. Which configuration should I do ?
localhost:50773/api/export/report/InsuranceHandlingFiles
You appear to be using atttribute routing already (in the form of [RoutePrefix]). You could switch to it completely. Instead of your current route configuration, you would simply do this:
config.MapHttpAttributeRoutes();
And then, to map a URL such as /api/export/report/InsuranceHandlingFiles, add an additional [Route] attribute to your controller method:
[RoutePrefix("api/export")]
public class ExportController : ApiController
{
[HttpPost, Route("report/{reportType}")]
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^
// add this
public HttpResponseMessage Report([FromBody]ReportInput input, string reportType)
{
…
}
}
If you want reportType to be optional, assign a default value to the string reportType parameter, and (if that isn't enough by itself), add a second route; e.g.:
[HttpPost, Route("report/{reportType}"), Route("report")]
public HttpResponseMessage Report([FromBody]ReportInput input, string reportType = null)
{
…
}

Webapi method Get with string parameter not getting invoked

I am creating asp.net webapi with two get methods. One returns all the records while the other should be filtering based on a string parameter called countrycode. I am not sure for what reason the get method with string parameter doesnt get invoked.
I tried the following uri's
http://localhost:64389/api/team/'GB'
http://localhost:64389/api/team/GB
Following is my code
Web API
public HttpResponseMessage Get()
{
var teams = _teamServices.GetTeam();
if (teams != null)
{
var teamEntities = teams as List<TeamDto> ?? teams.ToList();
if (teamEntities.Any())
return Request.CreateResponse(HttpStatusCode.OK, teamEntities);
}
return Request.CreateErrorResponse(HttpStatusCode.NotFound, "Team not found");
}
public HttpResponseMessage Get(string countryCode)
{
if (countryCode != null)
{
var team = _teamServices.GetTeamById(countryCode);
if (team != null)
return Request.CreateResponse(HttpStatusCode.OK, team);
}
throw new Exception();
}
WebAPIConfig
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
// Web API configuration and services
// Configure Web API to use only bearer token authentication.
config.SuppressDefaultHostAuthentication();
config.Filters.Add(new HostAuthenticationFilter(OAuthDefaults.AuthenticationType));
// Web API routes
config.MapHttpAttributeRoutes();
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
config.Formatters.JsonFormatter.SupportedMediaTypes
.Add(new MediaTypeHeaderValue("text/html"));
}
}
I think you are probably hitting the default 'Get()' method from your default API route.
I expect if you changed the parameter name to 'id' on your method like so, it would also work:
public HttpResponseMessage Get(string id)
This is because the optional parameter name in the default route is 'id'.
For attribute routing to work, you need to decorate your controller and methods with the values which were previously inferred by the route configuration.
So at the top of your controller, you would probably have:
[RoutePrefix("api/team")]
public class TeamController : ApiController
Then above your second get method:
[Route("{countryCode}")]
public HttpResponseMessage Get(string countryCode)
Since attribute routing, I haven't used the "old-style" routing.
Check out the ASP.NET page on attribute routing for more information.
Edit for comment:
If you have two routes which have the same parameters you need to differentiate them somehow in the route. So for your example of get by team name, I would probably do something like this:
[HttpGet()]
[Route("byTeamName/{teamName}")]
public HttpResponseMessage GetByTeamName(string teamName)
Your url would then be /api/team/byTeamName/...
Your other method name is "Get" and the default HTTP attribute routing looks for method names with the same as HTTP verbs. However you can name your methods anything you like and decorate them with the verbs instead.

WebAPI controller not working while another one does

I have an API that works fine locally and when I move it to the live environment it doesn't.
The main POST action on the affected controller returns:
NotFound
With a test GET action I get back:
"Message": "No HTTP resource was found that matches the request URI
Strangely, when I uploaded a testController with the same test action as used in the main controller I get a proper response from the API.
This is the test that works fine:
public class TestController : ApiController
{
[AllowAnonymous]
[HttpGet]
public HttpResponseMessage helloWorld()
{
return Request.CreateResponse(HttpStatusCode.OK, "HelloWorld!");
}
}
The controller which does not work:
public class DeviceController : ApiController
{
[AllowAnonymous]
[HttpGet]
public HttpResponseMessage helloWorld() // This returns: "No HTTP resource was found that matches the request URI 'http://api.mySite.com/api/Device/helloWorld'."
{
return Request.CreateResponse(HttpStatusCode.OK, "HelloWorld!");
}
[AllowAnonymous]
[HttpPost]
public HttpResponseMessage Login([FromBody] LoginObject loginObject) // This returns: "NotFound"
{
...
}
}
Here is the web config:
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
config.MapHttpAttributeRoutes();
config.Routes.MapHttpRoute(
name: "API Default",
routeTemplate: "api/{controller}/{action}/{id}",
defaults: new { id = RouteParameter.Optional }
);
}
}
Try to add explicitly declare of route like by acrion
[Route("api/Device/helloWorld")]
[AllowAnonymous]
[HttpGet]
public HttpResponseMessage helloWorld()
or
[RoutePrefix("api/Device")]
public class DeviceController : ApiController
and then
[Route("helloWorld")]
[AllowAnonymous]
[HttpGet]
public HttpResponseMessage helloWorld()
For poor sap's like myself in the future: Ensure the methods on your controller are public.
I spent some time looking for the answer to this problem in .NET 7.0 after I had made a new project (which automatically created a WeatherForecastController).
It turns out that the project had also automatically created a file named proxy.conf.js. In the file, the context: setting was set to "/weatherforecast". I changed it to "/api" instead and then changed [Route("[controller]")] to [Route("api/[controller]")] in both controller files. The controllers worked fine after that.

WebAPI error: When POST method is created - Multiple actions were found that match the request

I keep getting this error when I try to have a POST method with 2 "Get" methods
my WebAPI:
[ResponseType(typeof(Organization))]
[System.Web.Mvc.HttpPost]
[System.Web.Http.ActionName("CreateOrganization")]
public IHttpActionResult CreateOrganization(Organization org)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
helper.InsertOrganization(org);
return CreatedAtRoute("DefaultApi", new { id = org.Id }, org);
}
//GET: api/Products/5
[ResponseType(typeof(Organization))]
[System.Web.Mvc.HttpGet]
[System.Web.Http.ActionName("FindBy")]
public IHttpActionResult FindBy(int id)
{
Organization org = helper.QueryOnOrganizationBy(id);
if (org == null)
{
return NotFound();
}
return Ok(org);
}
[ResponseType(typeof(Organization))]
[System.Web.Http.ActionName("All")]
[System.Web.Mvc.HttpGet]
public IHttpActionResult All()
{
List<Organization> orgList = helper.QueryAllOnOrganization();
if (orgList == null)
{
return NotFound();
}
return Ok(orgList);
}
ERROR:
{
"Message": "An error has occurred.",
"ExceptionMessage": "Multiple actions were found that match the request: \r\nCreateOrganization on type ProductReviews.Controllers.OrganizationsController\r\nAll on type ProductReviews.Controllers.OrganizationsController\r\nQueryAllOnTable on type ProductReviews.Controllers.OrganizationsController\r\nOpenConn on type ProductReviews.Controllers.OrganizationsController\r\nCloseConn on type ProductReviews.Controllers.OrganizationsController",
"ExceptionType": "System.InvalidOperationException",
"StackTrace": " at System.Web.Http.Controllers.ApiControllerActionSelector.ActionSelectorCacheItem.SelectAction(HttpControllerContext controllerContext)\r\n at System.Web.Http.Controllers.ApiControllerActionSelector.SelectAction(HttpControllerContext controllerContext)\r\n at System.Web.Http.ApiController.ExecuteAsync(HttpControllerContext controllerContext, CancellationToken cancellationToken)\r\n at System.Web.Http.Dispatcher.HttpControllerDispatcher.<SendAsync>d__1.MoveNext()"
}
WEB API Route:
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
// Web API configuration and services
// Web API routes
config.MapHttpAttributeRoutes();
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
//To produce JSON format add this line of code
config.Formatters.JsonFormatter.SupportedMediaTypes.Add(new MediaTypeHeaderValue("text/html"));
}
}
If you want to use [ActionName] attributes on your controller actions, then your route template needs to include {action}:
routeTemplate: "api/{controller}/{action}/{id}",
The default template "api/{controller}/{id}" assumes that you will only use the HTTP method (e.g., GET or POST) and optional id to distinguish between actions.
Also, in Web API, you should use the HttpGet and HttpPost attributes from the System.Web.Http namespace, not System.Web.Mvc.

Resources