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
Related
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...
When using the following routes:
config.Routes.MapHttpRoute(
name: "new_device",
routeTemplate: "api/v1/devices",
defaults: new { controller = "Devices", action = "new_device" }
);
config.Routes.MapHttpRoute(
name: "devices_list",
routeTemplate: "api/v1/devices",
defaults: new { controller = "Devices", action = "devices_list", httpMethod = new HttpMethodConstraint(HttpMethod.Get) }
);
The controller looks as follows:
public class DevicesController : ApiController
{
[HttpPost]
[ResponseType(typeof(IHttpActionResult))]
[Route("api/v1/devices")]
[ActionName("new_device")]
[ValidateModel]
public IHttpActionResult NewDevice([System.Web.Http.FromBody] Device device )
{
...
}
[HttpGet]
[ResponseType(typeof(IHttpActionResult))]
[Route("api/v1/devices")]
[ActionName("devices_list")]
[ValidateModel]
public List<Device> GetAllDevices()
{
...
}
My expectation would be that the router would find the correct route based on the HttpMethod used since even it's using the same URI it is using a different HttpMethod.
But instead it fails with the following:
"Message": "The requested resource does not support http method 'GET'."
My guess is because it fins a match with the URI and then checks if the method if the same.
Is there a way to achieve using the same URI with different Http Method which is by the way REST guidelines? Am I missing something?
Ok , I check your whole code. I think you are trying to achieve the calls in complicated way.
Following code is for the configuration :
public static void Register(HttpConfiguration config)
{
// Web API configuration and services
// Web API routes
config.MapHttpAttributeRoutes();
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/v1/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
}
and follwoing is your controller code :
public class DevicesController : ApiController
{
[HttpPost]
[ResponseType(typeof(IHttpActionResult))]
[ActionName("newDevice")]
public IHttpActionResult NewDevice([System.Web.Http.FromBody] Device device)
{
return null;
}
[HttpGet]
[ResponseType(typeof(IHttpActionResult))]
[ActionName("devices_list")]
public List<Device> GetAllDevices()
{
return null;
}
}
I removed ValidateModel. I think it's your custom attribute or somehow related with built in nuget package.
Anyways, execute the calls with Postman or any HTTP client tool. It should work , as it was working at my end with above mentioned code.
Example Calls:
https://localhost:44370/api/v1/devices/devices_list = > Get.
https://localhost:44370/api/v1/devices/newDevice => Post. Provide body as post call for the object.
My Web API on an Asp.Net MVC web app is returning 404 error when receiving requests that don't specify any controller.
The calls that are returning 404 error are:
https://myWebApp/api/
The goal would be to handle these type of requests without returning error and return something like "true" or "new EmptyResult()".
Current routing for the Web API includes the following in WebApiConfig.cs
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
config.Filters.Add(new IdentityBasicAuthenticationAttribute());
config.MapHttpAttributeRoutes();
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
}
}
While I have routes explicitly defined for each API controller:
[IdentityBasicAuthentication]
[Authorize]
public class myApi1Controller : ApiController
{
[HttpGet]
[Route("api/myApi1")]
public string Get(string id) { ... }
}
I have tried to route these calls to a default API or MVC controller without success.
My current RouteConfig for the MVC app is:
public class RouteConfig
{
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 },
namespaces: new[] { "myWebApp.Controllers" }
);
}
}
The order in which these are called is:
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
GlobalConfiguration.Configure(WebApiConfig.Register);
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);
}
Create a controller to handle that route so it does not fail with not found
Like
[RoutePrefix("api")]
public class MyEmptyController : ApiController {
//GET api
[HttpGet]
[Route("")]
public IHttpActionResult Get() {
return StatusCode(HttpStatusCode.NoContent); //204
}
}
Using attribute routing as it is already enabled via config.MapHttpAttributeRoutes(); in WebApiConfig
Your route config is different from your WebApi config and I don't know the order that you are calling them.
in your RouteConfig:
url: "{controller}/{action}/{id}",
which means: http://localhost:PORTNUMBER/myApi1/ACTION
in your WebApiConfig
routeTemplate: "api/{controller}/{id}",
(method and id are optionals)
which means: http://localhost:PORTNUMBER/api/myApi1/?id=value
change your WebApiConfig, and you even will be able to avoid using the Route tag in your controller :
[IdentityBasicAuthentication]
[Authorize]
public class myApi1Controller : ApiController
{
[HttpGet]
public string Get(string id) {
return "works!";
}
}
Edit:
Keep every thing the same, Invoke your default GET method from:
http://localhost:PORTNUMBER/api/myApi1
Working in ASP.NET 4.6 here.
I have a controller:
public class ComputerController : ApiController
{
...
[HttpGet]
[Route("api/computer/ping")]
public IHttpActionResult Ping(int id)
{
return Ok("hello");
}
...
}
Going mostly from this answer (look at MSTdev's answer), I have this in my WebApiConfig.cs:
// So I can use [Route]?
config.MapHttpAttributeRoutes();
// handle the defaults.
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
The route doesn't work. I always get
No HTTP resource was found that matches the request URI
'http://localhost:29365/api/computer/ping'.
This seems like such a simple problem, yet I remain stumped. Any help?
Your route is missing the {id} parameter.
Ex.
[Route("api/category/{categoryId}")]
public IEnumerable<Order> GetCategoryId(int categoryId) { ... }
Your controller should look like this:
public class ComputerController : ApiController
{
...
[HttpGet]
[Route("api/computer/ping/{id}")]
public IHttpActionResult Ping(int id)
{
return Ok("hello");
}
...
}
My API controllers are never getting instantiated even though i've made sure several times that my routes should be correct according to this and this question.
public void Configuration(IAppBuilder app)
{
var config = new HttpConfiguration();
config.Routes.MapHttpRoute("DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
app.UseWebApi(config);
}
This is what my controller looks like:
class RaspberryController : ApiController
{
public HttpResponseMessage Get()
{
return new HttpResponseMessage
{
Content = new StringContent("Test from Owin")
};
}
}
As you can see it's extremely simple. What could possibly be wrong?
I realized that my controller class were implicitly internal since I didnt specify otherwise. It must be public in order for Owin to find the class by reflection. Thus it had nothing to do with routing...
public class RaspberryController : ApiController
{
public HttpResponseMessage Get()
{
return new HttpResponseMessage
{
Content = new StringContent("Test from Owin")
};
}
}