WebAPI No action was found on the controller by passing parameters - c#

HomeController.cs
class HomeController : ApiController
{
[HttpGet]
public IHttpActionResult GetData(string name)
{
if (string.IsNullOrWhiteSpace(name))
{
throw new ArgumentNullException("username can not be empty");
}
return Ok("Test Done");
}
}
StartUp.cs
public void Configuration(IAppBuilder appBuilder)
{
HttpConfiguration config = new HttpConfiguration();
config.MapHttpAttributeRoutes();
config.Routes.MapHttpRoute(
name: "GetData",
routeTemplate: "V2/{controller}/{name}",
defaults: new { controller = "Home", action = "GetData" }
);
appBuilder.UseWebApi(config);
}
Getting error:
{
"Message": "No HTTP resource was found that matches the request URI 'http://localhost:4057/V2/Home/GetData/'.",
"MessageDetail": "No type was found that matches the controller named 'Home'."

The problem here is simple.
The access modifier of your class is very restrictive
class HomeController : ApiController
{
The default access modifier is internal, meaning it is not publicly accessible.
Try to change the access modifier to public to expose the service publicly.
public class HomeController : ApiController
{
I can replicate your issue using postman and my existing web API.
Error from my postman:

Try changing the method name to Get (more about http://www.asp.net/web-api/overview/web-api-routing-and-actions/routing-in-aspnet-web-api).
Also setting the attribute routing might help if you do not want to change the method name (http://www.asp.net/web-api/overview/web-api-routing-and-actions/attribute-routing-in-web-api-2).

As Sherlock mentioned, the API Controller must be public. However, consider using attribute routing over convention routing since its much less error prone:
HomeController.cs:
[RoutePrefix("V2/Home")]
public class HomeController : ApiController
{
[HttpGet]
[Route("{name}", Name = "GetData")]
public IHttpActionResult GetData(string name)
{
if (string.IsNullOrWhiteSpace(name))
{
throw new ArgumentNullException("username can not be empty");
}
return Ok("Test Done");
}
}
Startup.cs:
public void Configuration(IAppBuilder appBuilder)
{
HttpConfiguration config = new HttpConfiguration();
config.MapHttpAttributeRoutes();
appBuilder.UseWebApi(config);
}

Related

Overriding WebAPI controller naming convention doesn't work

I am having difficulties to understand how WebAPI routing is working. This is what my controller looks like:
[RoutePrefix("order-mgmt")]
public class OrderController : ApiController
{
[HttpGet]
[Route("execute")]
public HttpResponse ExecOrder(string clordid)
{
// ...
return Request.CreateResponse(HttpStatusCode.NoContent);
}
[HttpGet]
[Route("reject")]
public HttpResponse RejectOrder(string clordid)
{
// ...
return Request.CreateResponse(HttpStatusCode.NoContent);
}
}
And this is my Startup class and configuration
public class Startup
{
public void Configuration(IAppBuilder appBuilder)
{
// Configure Web API for self-host.
var config = new HttpConfiguration();
config.MapHttpAttributeRoutes();
config.Routes.MapHttpRoute(
name: "ActionApi",
routeTemplate: "api/{controller}/{action}/{id}",
defaults: new { id = RouteParameter.Optional }
);
appBuilder.UseWebApi(config);
}
}
I was expecting that I am able to reach public HttpResponseMessage ExecOrder(string clordid) via http://localhost:port/api/order-mgmt/execute?clordid=<clordidstring>.
This however doesn't work. The controller is still only reachable via api/order/execute. I really don't get what I am doing wrong here. Any help is greatly appreciated.
try removing [RoutePrefix("order-mgmt")]
then do it like this
[Route("api/order-mgmt/execute/{clordid}")]
public HttpResponse ExecOrder(string clordid)
// then you can reach it in this route
// api/order-mgmt/execute/YOUR_STRING

Connecting to WebAPI2 endpoints(routes) throw Http code 503 for a controller and another controller works fine

I am using Owin self-hosting with WebAPI2.
I have two controller classes and using attribute routing.
One of them has following signature:
[RoutePrefix("api/v1/devices")]
public class DeviceController : ApiController
{
[HttpPost]
[Route("")]
public async Task<HttpResponseMessage> DevicePresence()
{
...
}
[HttpGet]
[Route("updates/{deviceID}")]
public HttpResponseMessage GetDeviceUpdates(string deviceID)
{
...
}
}
This one is working fine and action methods get triggered.
The other Controller has below signature:
[RoutePrefix("device/class")]
public class RemoteController : ApiController
{
[HttpGet]
[Route("remotehost")]
public HttpResponseMessage RemoteHost()
{
...
}
[HttpGet]
[Route("version")]
public HttpResponseMessage GetVersion()
{
...
}
}
When I try to connect to any of these I get 503 (Service Unavailable) response.
My Startup class is initialized as below:
public class Startup
{
public static void Configuration(IAppBuilder app)
{
var config = new HttpConfiguration();
config.MapHttpAttributeRoutes();
config.Formatters.Add(new JsonMediaTypeFormatter());
config.Formatters.Remove(config.Formatters.XmlFormatter);
config.EnsureInitialized();
app.UseWebApi(config);
}
}
I tried to use the conventional routing as well but still the same problem.
config.Routes.MapHttpRoute(
name: "RemoteApi",
routeTemplate: "device/{controller}/{action}"
);
public class ClassController : ApiController
{
public HttpResponseMessage GetVersion()
{
...
}
}
This is also throwing 503 status code
If I change the Route prefix in the second controller as below then it's working:
[RoutePrefix("api/v1/device/class")]
public class RemoteController : ApiController
{
...
}
As per my requirement, I couldn't change the endpoints.
I am not sure what's wrong here and any help would be much appreciated.
Your RemoteController throws an exception because you do not follow naming conventions of WEB API.
Your RemoteHost() method which is a get method has to have a "Get" prefix, so its name is supposed to actually be GetRemoteHost().
That should solve it.
In case you want to alter the naming conventions, you can modify route definitions in the global.asax file:
Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{action}/{id}",
defaults: new { action = "get", id = RouteParameter.Optional }
);
Hope that helped.
I realized it was not a problem with webapi or routing.
Actually, I was adding a firewall exception for the URL's and somehow it was not getting removed from firewall settings and keeps an entry in DACL.
I removed this from cmd prompt and now everything works fine.
Sorry for bothering...

Web API 2 - Error: "No type was found that matches the controller named 'resize'."

I am trying to just do a simple file upload API using Web API.
Here is the Controller:
[RoutePrefix("api/resize")]
public class ResizeController : ApiController
{
[HttpPost, Route("api/resize/preserveAspectRatio")]
public async Task<IHttpActionResult> resizePreserveAspectRatio()
{
if (!Request.Content.IsMimeMultipartContent())
throw new HttpResponseException(HttpStatusCode.UnsupportedMediaType);
int maxWidth = 100;
int maxHeight = 100;
var provider = new MultipartMemoryStreamProvider();
await Request.Content.ReadAsMultipartAsync(provider);
foreach (var file in provider.Contents)
{
var filename = file.Headers.ContentDisposition.FileName.Trim('\"');
var buffer = await file.ReadAsByteArrayAsync();
//Do whatever you want with filename and its binaray data.
}
return Ok();
}
}
This is my WebApiConfig:
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 }
);
}
}
When I POST a file with PostMan, here is the error I get:
{
"Message": "No HTTP resource was found that matches the request URI 'http://localhost:26303/api/resize/preserveAspectRatio'.",
"MessageDetail": "No type was found that matches the controller named 'resize'."
}
This is not a dupe - was not able to find another article that addresses this specific combination.
This as you would expect is a routing issue. The comments have already identified that you have conflicts with your route and route prefix attributes resulting in the following route
api/resize/api/resize/preserveAspectRatio
being mapped to your action.
To get the desired route, you can either remove the prefix from the controller itself.
//removed prefix
public class ResizeController : ApiController {
//Matches POST api/resize/preserveAspectRatio
[HttpPost, Route("api/resize/preserveAspectRatio")]
public async Task<IHttpActionResult> resizePreserveAspectRatio() {
//...removed for brevity
}
}
Or Remove it from the route on the method
[RoutePrefix("api/resize")]
public class ResizeController : ApiController {
//Matches POST api/resize/preserveAspectRatio
[HttpPost, Route("preserveAspectRatio")]
public async Task<IHttpActionResult> resizePreserveAspectRatio() {
//...removed for brevity
}
}
Or override the route prefix by using tilde (~) on the method attribute
[RoutePrefix("api/resize")]
public class ResizeController : ApiController {
//Matches POST api/resize/preserveAspectRatio
[HttpPost, Route("~/api/resize/preserveAspectRatio")]
public async Task<IHttpActionResult> resizePreserveAspectRatio() {
//...removed for brevity
}
}
Reference Attribute Routing in ASP.NET Web API 2

No action was found on the controller 'Tickets' that matches the name 'CloseTicket'

I am writing a webapi project and am receiving the error No action was found on the controller 'Tickets' that matches the name 'TestMethod' whenever I try any of the methods in the controller.
None of the actions in the below controller are working.
I have been googling and have already setup WebApiConfig.cs to add action to the routing.
Is there something else I am missing.
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{action}/{id}",
defaults: new { id = RouteParameter.Optional });
config.EnableSystemDiagnosticsTracing();
}
}
Controller
public class TicketController : ApiController
{
[HttpPost]
public static ServiceResponse<string> IssueTicket([FromBody]ServiceRequest<TicketRequest> request)
{
return ServiceResponse<string>.WithPayload(ticketID);
}
[HttpPost]
public static ServiceResponse<bool> CheckTicketExist([FromBody]ServiceRequest<string> request)
{
return ServiceResponse<bool>.WithPayload(doesExist);
}
[HttpPost]
public static ServiceResponse<bool> CloseTicket([FromBody]ServiceRequest<string> request)
{
return ServiceResponse<bool>.WithPayload(result);
}
[HttpPost]
public static bool TestMethod([FromBody]string test)
{
return true;
}
}
Web API doesn't consider static methods while selecting actions.
Reference
Which methods on the controller are considered "actions"? When selecting an action, the framework only looks at public instance methods on the controller.
Remove the static keyword from your controller.

Web Api 2 set route to ApiController method dynamically at runtime

I would like to set the route to a method within an ApiController dynamically. The below shows my TokenController:
public class TokenController : ApiController
{
[Route("api/token/{grantType}")]
[RequireHttps]
public IHttpActionResult Post(string grantType)
{}
}
I am thinking of using dependency injection as follows:
public class TokenController : ApiController
{
public TokenController(ITokenService tokenService)
{
//configure route "api/token/{grantType}" using tokenService?
}
[Route("api/token/{grantType}")]
[RequireHttps]
public IHttpActionResult Post(string grantType)
{}
}
Or do I need to do this in App_Start using the HttpConfiguration object?
How would I do this?
Found my answer. I will configure the endpoint route with HttpConfiguration:
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
config.Routes.MapHttpRoute(
name: "API TokenEndpoint",
routeTemplate: "services/newtoken/{grantType}",
defaults: new { controller = "Token" action="Post"},
constraints: null);
}
}

Categories