Setting up custom API route - c#

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");
}
...
}

Related

Added a second controller to my WebAPI and it is not working

Added a second controller in my WebAPI project and it is nor working completely but the first controller is working as expected
The default URI works for the first controller to return all records:
http://localhost:59654/api/TidalBatch
The second controller does not work and returns the error in question:
http://localhost:59654/api/TidalBatchConsolidated
However, if I pass in {id} for it, it does work for when I use the id (example shown):
http://localhost:59654/api/TidalBatchConsolidated/BAM
Tried modifying the routing addresses
WebAPI config:
config.MapHttpAttributeRoutes();
config.Routes.MapHttpRoute(
name: "TidalBatchApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
config.Routes.MapHttpRoute(
name: "TidalBatchConsolidatedApi",
routeTemplate: "api/TidalBatchConsolidated/{id}",
defaults: new { id = RouteParameter.Optional }
);
I have 2 controllers, TidalBatchController.cs and TidalBatchConsolidatedController.cs. Both inherit from ApiController class.
Here's an example of my second controller that is not working as expected:
public class TidalBatchConsolidatedController : ApiController
{
public TidalBatchConsolidated GetAll(string id)
{
using (BDW_ProcessingEntities_TidalBatch entities = new BDW_ProcessingEntities_TidalBatch())
{
return entities.TidalBatchConsolidateds.FirstOrDefault(e => e.CompanyAbbr == id);
}
}
}
When I navigate to the base controller in the address it should return the List results in JSON format based on which entity data model is being passed in.
First, the order you register routes is important where more generic routes need to be registered after more specific routes. Secondly you more specific route needs controller in order for it to match.
config.MapHttpAttributeRoutes();
config.Routes.MapHttpRoute(
name: "TidalBatchConsolidatedApi",
routeTemplate: "api/TidalBatchConsolidated/{id}",
defaults: new { controller ="TidalBatchConsolidated", id = RouteParameter.Optional }
);
config.Routes.MapHttpRoute(
name: "TidalBatchApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
The controller also needs to ensure that there is a matching action
For example
public class TidalBatchConsolidatedController: ApiController {
[HttpGet]
public IHttpActionResult Get() {
//...
}
[HttpGet]
public IHttpActionResult Get(string id) {
//...
}
}
Since you have attribute routing enabled with config.MapHttpAttributeRoutes();, you could forego convention based route and use attribute routing on the controller instead
[RoutePrefix("api/TidalBatchConsolidated")]
public class TidalBatchConsolidatedController: ApiController {
//GET api/TidalBatchConsolidated
[Route("")] //Default route
[HttpGet]
public IHttpActionResult GetAll() {
//...
}
//GET api/TidalBatchConsolidated/BAM
[Route("{id}")]
[HttpGet]
public IHttpActionResult Get(string id) {
//...
}
}
Reference Attribute Routing in ASP.NET Web API 2

C# REST API Controller: same route with 2 different actions

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.

Web api routing - default actions with custom actions mapped twice

I have the following routes mapped in my WebApiConfig:
config.Routes.MapHttpRoute(name: "WithActionApi", routeTemplate: "api/{controller}/{action}/{id}");
config.Routes.MapHttpRoute(name: "DefaultApi", routeTemplate: "api/{controller}/{id}", defaults: new { action = "DefaultAction", id = RouteParameter.Optional });
An in my controller I have:
[HttpGet]
public ProspectAddressResult Addresses(int id)
{
...
return result;
}
[ActionName("DefaultAction")]
public ProspectDetail Get(int id)
{
...
return prospect;
}
I'm finding that i'm getting the Get route mapped twice once as api/prospect/1 and api/prospect/Get/1. What am I doing wrong as I would expect the route to only be mapped once i.e. api/prospect/1 or is that not possible (or relevant)?
Why not just install web api 2 through nuget. Then you can use the Route and RoutePrefix properties on your actions/controllers to specify your routes.
You should then never get duplicate mapping
Here's an example of how your api controller would be set up:
[RoutePrefix("api/prospect")]
public class ProspectController: ApiController
{
[Route("{id}")]
public ProspectDetail Get(int id)
{
...
return prospect;
}
}
Your route for that would then be api/prospect/1

UriPathExtensionMapping in WebAPI 2

Weird stuff is going on when I try to add extension mapping features to my api. Some things work but I cant get anything to properly return JSON. These related questions haven't gotten me where I need to go:
UriPathExtensionMapping to control response format in WebAPI
UriPathExtensionMapping in MVC 4
My project has both HttpRoutes and HttpAttributeRoutes enabled. Not sure if that matters - I am just using the default WebApi project template. I've got the following routes:
// Web API routes
config.MapHttpAttributeRoutes();
config.Routes.MapHttpRoute(
name: "Api UriPathExtension",
routeTemplate: "api/{controller}.{ext}",
defaults: new { }
);
config.Routes.MapHttpRoute(
name: "Api UriPathExtension ID 1",
routeTemplate: "api/{controller}.{ext}/{id}",
defaults: new { id = RouteParameter.Optional }
);
config.Routes.MapHttpRoute(
name: "Api UriPathExtension ID 2",
routeTemplate: "api/{controller}/{id}.{ext}",
defaults: new { id = RouteParameter.Optional }
);
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
Here's my controller:
[RoutePrefix("api/roundTypes")]
public class RoundTypesController : ApiController
{
// GET api/roundTypes
[Route("")][HttpGet]
public IQueryable<Vcijis.RoundType> GetAllRoundTypes()
When I test it:
http://localhost/api/roundTypes **works** but is XML
http://localhost/api/roundTypes/ **works** (also XML)
http://localhost/api/roundTypes.json returns **404**
http://localhost/api/roundTypes.json/ returns a **JSON formatted error**
The JSON error message I get is:
{"message":"No HTTP resource was found that matches the request URI
'http://localhost/api/roundTypes.json/'.",
"messageDetail":"No action was found on the controller 'RoundTypes'
that matches the request."}
I've also tried with an id parameter and get similar results. I can't seem to get {ext} working in HttpAttributeRoutes at all. Help?
Attributed controllers/actions cannot be reached from routes matched to conventional ones. So you would need to use attribute routing to specify the {ext} in your route templates.
One example:
[RoutePrefix("api/customers")]
public class CustomersController : ApiController
{
[Route("~/api/customers.{ext}")]
[Route]
public string Get()
{
return "Get All Customers";
}
[Route("{id}.{ext}")]
[Route("{id}")]
public string Get(int id)
{
return "Get Single Customer";
}
[Route]
public string Post(Customer customer)
{
return "Created Customer";
}
[Route("{id}")]
public string Put(int id, Customer customer)
{
return "Updated Customer";
}
[Route("{id}")]
public string Delete(int id)
{
return "Deleted Customer";
}
}

How to correctly configure a route issue in ASP.Net WebApi

After developing a simple test ASP.Net WebApi solution to implement Unity interface DI into my Controller I have hit an issue with getting my API to route to the relevant methods correctly.
Typing in the following URL will return the first GET method as expected:
http://localhost:1035/api/values
Typing in a parameter to hit the GetSelectedPerson method in the controller is never registered:
http://localhost:1035/api/values/Test
Hopefully someone can tell me where I'm going wrong, heres the relevant code.
RouteConfig from the App_Start folder:
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 }
);
}
}
Here is the WebApi config again from the App_Start folder:
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new
{
id = RouteParameter.Optional
}
);
config.Formatters.Remove(config.Formatters.XmlFormatter);
}
}
Here are the two GET HTTP methods I've implemented within the 'Values' controller:
public class ValuesController : ApiController
{
private IPersonCreator _createPerson;
public ValuesController(IPersonCreator createPerson)
{
_createPerson = createPerson;
}
//GET api/values
public IPerson Get()
{
return _createPerson.CreateNewPerson();
}
//**********Issue: This Method is never hit.**********
public IPerson GetSelectedPerson(string nameOfPerson)
{
IPerson selectedPerson = null;
var returnedPeople = _createPerson.CreateNewPeople();
foreach (var person in returnedPeople)
{
if (person.Name == "John")
{
selectedPerson = person;
}
}
return selectedPerson;
}
This is a parameter binding problem. In the default route the expected parameter name is id, however, in your action you have nameOfPerson.
You have two options here, you can either rename your nameOfPerson parameter to be id i.e.
public IPerson GetSelectedPerson(string id)
or alternatively add a specific route which expects a nameOfPerson parameter i.e.
// place after default route
config.Routes.MapHttpRoute(
name: "PersonByNameApi",
routeTemplate: "api/{controller}/{nameOfPerson}",
defaults: new
{
nameOfPerson = RouteParameter.Optional
}
);

Categories