WebAPI route to root URL - c#

I have a WebAPI application that is used for some RESTful operations in the database. It works great, but I want to match a route with the root URL. For example, I want to go to the root of the site and see some useful information that are dynamically generated.
Currently, I have it setup so that it follows the standard convention of api/{controller}/{action}, but how can I show this information when navigated to the root instead of something like api/diagnostics/all?
Basically what I want is, when the user navigates to the root URL, I want to route that request to TestController.Index()
I have the following setup in the WebApiConfig.cs file:
public static void Register(HttpConfiguration config)
{
// Web API routes
config.MapHttpAttributeRoutes();
config.Routes.MapHttpRoute(
name: "Index",
routeTemplate: "",
defaults: new { controller = "Test", action = "Index" }
);
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional, controller = "Test" }
);
}
And this is what my TestController.cs looks like:
[RoutePrefix("api")]
public class TestController : ApiController
{
[Route("TestService"), HttpGet]
public string Index()
{
return "Service is running normally...";
}
}

You could also simply use ([Route("")]):
public class TestController : ApiController
{
[Route(""), HttpGet]
public string Index()
{
return "Service is running normally...";
}
}

You can add a route for the default URL in WebApiConfig.cs. Here's an example where the root URL is mapped to method HomeController.Index():
config.Routes.MapHttpRoute(
name: "Root",
routeTemplate: "", // indicates the root URL
defaults: new { controller = "Home", action = "Index" } // the controller action to handle this URL
);

Basically what I want is, when the user navigates to the root URL, I
want to route that request to TestController.Index()
In this case make sure that you have not decorated your TestController.Index action with this attribute:
[Route("TestService")]
So here's how your TestController might look like:
[RoutePrefix("api")]
public class TestController : ApiController
{
[HttpGet]
public string Index()
{
return "Service is running normally...";
}
}
And now simply navigate to / or /api.

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.

Get method not working in web api

Hi I am developing one application in web api2 and angularjs. I have some routing problems in accessing urls from angularjs.
I am trying to access below url.
var url = '/api/projects/4/processes';
My controller code looks like below.
[RoutePrefix("api/processes")]
public class processesController : ApiController
{
[ActionName("projects/{projectsId}/processes")]
public HttpResponseMessage Get(int id)
{
return Request.CreateResponse(HttpStatusCode.OK, "");
}
}
I am getting 404 error. I am not able to hit the url.
This is my webapi.config file.
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
//routeTemplate: "{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
Any help would be appreciated.
First ensure that attribute routing is enabled before convention-based routes.
config.MapHttpAttributeRoutes();
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
if the intended url is /api/projects/4/processes Then the given action needs to update its route template to match. The controller already has a route prefix but that can be overridden by prefixing the route template with the tilde ~
Use a tilde (~) on the method attribute to override the route prefix:
//GET /api/projects/4/processes
[HttpGet]
[Route("~/api/projects/{projectsId:int}/processes")]
public HttpResponseMessage Get(int projectsId) { ... }
Source: Attribute Routing in ASP.NET Web API 2
In your case, the URL should be,
http://yourUrl/api/processes?projectsId=yourValue
Also, change your ActionName to Route attribute,
[RoutePrefix("api/processes")]
public class ProcessesController : ApiController
{
[Route("projects/{projectsId}/processes"),HttpGet]
public HttpResponseMessage Get(int projectsId)
{
return Request.CreateResponse(HttpStatusCode.OK, "");
}
}
New URL - http://yourUrl/api/processes/projects/2/processes
More info on Attribute routing
Please make sure that attribute routing should be enabled before convention-based routes.
config.MapHttpAttributeRoutes();
then you can make routing
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
Define Methods like :
//GET /api/projects/4/processes ([ActionName("projects/{projectsId}/processes")])
[RoutePrefix("api/processes")]
public class processesController : ApiController
{
[HttpGet]
[Route("~/api/projects/{projectId:int}/processes")]
public HttpResponseMessage Get(int projectId) { ... }
}
You have a route prefix, which means the url of action would be RoutePrefix + ActionRoute
i.e. HTTP GET api/processes/projects/{projectsId}/processes
Ref docs
Comment out the "[Authorize]" attribute on the ValuesController class was all I needed...
All credit to DotNetTutorials
From the article:
“api/{controller}/{id}”
At this point, if you use the following URI in the browser, you will get an error stating – Authorization has been denied for this request.
http://localhost:xxxxx/api/values
To get rid of this error, comment Authorize attribute on the ValuesController class. This is related to security which we will discuss in a later article.

Multiple actions were found that match the request when using actions in Route config

I'm currently building an API using Web API 2.2
I have the RESTful part of it working but now I need one non-RESTful controller:
public class PremisesController : ApiController
{
private PremiseService _service;
public PremisesController()
{
_service = new PremiseService();
}
[HttpGet]
public IHttpActionResult Premise(string id)
{
id = id.Replace(" ", String.Empty).ToUpper();
List<Premise> premises = _service.GetPremisesForPostcode(id);
return Ok(premises);
}
[HttpGet]
public IHttpActionResult Building(string id)
{
double premise = Convert.ToDouble(id);
Building building = _service.GetBuildingsForPremise(premise);
return Ok(building);
}
}
The routing config is as follows:
config.MapHttpAttributeRoutes();
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
config.Routes.MapHttpRoute(
name: "ActionApi",
routeTemplate: "api/{controller}/{action}/{id}",
defaults: new { id = RouteParameter.Optional }
);
Im getting the error that it can't distinguish between the two methods when I initiate a GET action:
Multiple actions were found that match the request
So my question is Do I need to specify the Route attribute on top of each method and if yes, why? Doesn't the second route (ActionApi) deals with that situation?
EDIT:
I just tested you're code and it works the way it is... maybe just it is unclear.
/api/Premises/Premise/8 --> will take you to your first action
/api/Premises/Building/8 --> will take you to your second action
/api/Premises/8 --> will cause error because the routing will go to the first rule api/{controller}/{id} with a GET request, then he can't distinguish which of the actions you want because they both match the first route: (api/Premises/{id})
You could also use the RoutePrefix attribute on your controller.
[RoutePrefix("api/premises")]
public class PremisesController : ApiController
That combined with the route attribute would mean you shouldn't get multiple actions with the same route

Web API route being ignored

I have these two routes defined:
routes.MapRoute(
name: "GetVoucherTypesForPartner",
url: "api/Partner/{partnerId}/VoucherType",
defaults: new { controller = "Partner", action = "GetVoucherTypesForPartner"}
);
routes.MapRoute(
name: "Default",
url: "api/{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional}
);
In my PartnerProfile controller, I have 2 methods:
public Partner Get(string id)
{ }
public IEnumerable<string> GetVoucherTypesForPartner(string id)
{ }
If I hit the url ~/api/Partner/1234 then, as expected, the Get method is called.
However, if I hit the url ~/api/Partner/1234/VoucherType then the same Get method is called. I am expecting my GetVoucherTypesForPartner to be called instead.
I'm pretty sure something in my route setup is wrong...
You seem to have mapped standard MVC routes, not Web API routes. There's a big difference. The standard routes are used by controllers deriving from the Controller class, but if you are using the ASP.NET Web API and your controllers are deriving from the ApiController type then you should define HTTP routes.
You should do that in your ~/App_Start/WebApiConfig.cs and not inside your ~/App_Start/RouteConfig.cs.
So go ahead:
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
config.Routes.MapHttpRoute(
name: "GetVoucherTypesForPartner",
routeTemplate: "api/Partner/{partnerId}/VoucherType",
defaults: new { controller = "Partner", action = "GetVoucherTypesForPartner" }
);
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
}
}
and then:
public class PartnerController : ApiController
{
public Partner Get(string id)
{
...
}
public IEnumerable<string> GetVoucherTypesForPartner(string partnerId)
{
...
}
}
Things to notice:
We have defined HTTP routes not standard MVC routes
The parameter that the GetVoucherTypesForPartner action takes must be called partnerId instead of id in order to respect your route definition and avoid any confusions

Categories