Routing Post to a non standard uri web api - c#

I´m writing a REST web api and I need to have an endpoint like /api/users/{id}/modify or http://localhost:8080/api/users/6/modify using a POST method.
I have a UsersController class with al read/write actions but I´m only able to access the post method by accessing /api/users, not /api/users/6/modify. I need to expand the hierarchy(if that is well said).
How can I do to achieve this?

You can use the Attribute Routing of asp.net web api.
The first thing is to enable it over the HttpConfiguration, in asp.net web api template, you can see it on the WebApiConfig.cs file.
using System.Web.Http;
namespace WebApplication
{
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
// Web API routes
config.MapHttpAttributeRoutes();
// Other Web API configuration not shown...
}
}
}
After that you can define a controller which should inherits from ApiController and you can use the Route attribute to define a custom route, for sample:
[RoutePrefix("api/users")]
public class UsersController : ApiController
{
[HttpPost]
[Route("{id}/modify")]
public HttpResponseMessage PostModify(int id)
{
// code ...
}
}
The RoutePrefix will define a prefix for all actions on the controller. So, to access the PostModify you should use a route like /api/users/6/modify in a post action. If you do not want it, just remove the RoutePrefix and define the complete url on the route attribute, like this: /api/users/{id}/modify.
You also can guarantee the type of the id argument defining a route like this:
[RoutePrefix("api/users")]
public class UsersController : ApiController
{
[HttpPost]
[Route("{id:int}/modify")]
public HttpResponseMessage PostModify(int id)
{
// code ...
}
}

Related

ASP.NET Core routing return 404

I am creating a web api using ASP.NET Core 3.1 and am trying to route URL to controllers. So far I have a basic controller like this:
[Route("abc")]
[ApiController]
public class ABCController : ControllerBase
{
// GET: abc/1234
[HttpGet("{id}")]
public async Task<ActionResult<string>> GetABCService(long id)
{
...
}
}
Which correctly route me to the page when I type in http://myurl/abc/1234. The next thing I controller I wanted to wire is like this:
[Route("xxx")]
[ApiController]
public class XXXController : ControllerBase
{
// GET: abc/1234/XXX
[HttpGet("{id}")]
public async Task<ActionResult<string>> GetXXXService(long id)
{
...
}
}
Somehow it keeps giving me 404 when I type in http://myurl/abc/1234/xxx. I made the first one works by setting my endpoint like this :
app.UseEndpoints(endpoints =>{
endpoints.MapControllerRoute(
"abc",
"abc/{id}",
new {controller = "ABCController", action = "GetABCService"});
//My current endpoint mapping for the second controller:
endpoints.MapControllerRoute(
"xxx",
"abc/{id}/xxx",
new {controller = "XXXController", action = "GetXXXStatus" });
}
I could not figure out why I would get 404 with http://myurl/abc/1234/xxx. Any insight?
You want to say XXXController to route 'abc' first by [Route("abc")]
[Route("abc")]
[ApiController]
public class XXXController : ControllerBase
{
[HttpGet("{id}/xxx")]
public ActionResult<string> GetXXXService(long id)
{
return "ActionResult";
}
}
When you use attribute routing, e.g. with [Route] or [HttpGet(…)], then convention-based routing is ignored. So the route templates you define with MapControllerRoute are not taken into account when generating the routes for your API controller. In addition, using the [ApiController] attribute actually enables certain API-related conventions. And one of those convention is that you may only use attribute routing for your API controllers.
So if you only have API controllers in your project, then you can leave out the MapControllerRoute calls. Instead, you will have to make sure that your attribute routing is correct.
In your case, if you want the route abc/1234/XXX to work, then you will have to use a route of abc/{id}/XXX.

ASP.NET Core Web API custom route not working

I have a ASP.NET Core Web API project, and the following controller:
[Route("/api/v0.1/controller")]
[ApiController]
public class MyController : ControllerBase
{
[HttpGet("/test")]
public ActionResult Test() { return null; }
}
but when I run the project, at /api/v0.1/controller/test I get "page not found" and I don't see where I made a mistake.
Your method route template contains prefixed /, due to that, the app route couldn't find the appropriate path.
Modify test method route template as follows.
[HttpGet("test")]
public ActionResult Test() { return null; }
More at Routing to controller actions in ASP.NET Core

How does ASP.NET Core Web API build URLs?

I have the following code:
[Produces("application/json")]
[Route("api/[controller]")]
public class MarketReportInstancesTableController : BaseController
{
internal readonly MyIRIntegrationDbContext Context;
public MarketReportInstancesTableController(ILogger<MarketReportInstancesTableController> logger,
MyIRIntegrationDbContext context) : base(logger)
{
Context = context;
}
[HttpGet (Name ="PageData")]
public IActionResult PageData([FromQuery] IDataTablesRequest request)
{
.... methd body in here
}
And I try to access with a URL like:
http://somehost/pca/api/MarketReportInstancesTable/pagedata
Which DOES NOT work, but
http://somehost/pca/api/MarketReportInstancesTable/
DOES WORK.
My question would be, why does the route do that? I want to have many paths in the same WebAPI controller.
Am I approaching it wrong?
You have no route template in the route. You only have a route name
Route names can be used to generate a URL based on a specific route. Route names have no impact on the URL matching behavior of routing and are only used for URL generation. Route names must be unique application-wide.
emphasis mine
//GET api/MarketReportInstancesTable/pagedata
[HttpGet ("pagedata", Name ="PageData")]
public IActionResult PageData([FromQuery] IDataTablesRequest request) {
//.... methd body in here
}
Using [HttpGet] without a route template is the same as [HttpGet("")] which will map to the root of the controller with route prefix.
This explains why your root call works.
Reference Routing in ASP.NET Core
Reference Routing to Controller Actions

Mixing WebAPI and MVC AttributeRouting with Route Prefix?

I'm pretty new to setting up routes and routing in MVC. At my last job we used attribute routing for our WebAPI stuff, so I'm pretty familiar with that (RoutePrefix, Route, and HttpGet/HttpPost attributes, etc). And I can get my current project to work just fine with attributes.
So now what I want to do is "prefix" all of the webApi routes with "api". So instead of going to mysite/test/hello, I want to go to mysite/api/test/hello.
This is what I have, using only attribute routing, and it works just fine:
[RoutePrefix("Test")]
public class TestController : ApiController
{ ....
[HttpPost]
[Route("{message}")]
public HttpResponse EchoBack(string message)
{
// return message ... in this case, "hello"
}
}
Now, I know I can change the RoutePrefix to "api/Test" (which works 100%), but I don't want to change all my controllers, I would rather be able to perform this by changing the values passed in to config.Routes.MapHttpRoute in WebApiConfig.
Is this possible?
What you describe can be done in attribute routing by using what is referred to as a global route prefix.
Referencing this article Global route prefixes with attribute routing in ASP.NET Web API
Create a DirectRouteProvider
public class CentralizedPrefixProvider : DefaultDirectRouteProvider {
private readonly string _centralizedPrefix;
public CentralizedPrefixProvider(string centralizedPrefix) {
_centralizedPrefix = centralizedPrefix;
}
protected override string GetRoutePrefix(HttpControllerDescriptor controllerDescriptor) {
var existingPrefix = base.GetRoutePrefix(controllerDescriptor);
if (existingPrefix == null) return _centralizedPrefix;
return string.Format("{0}/{1}", _centralizedPrefix, existingPrefix);
}
}
To quote article.
The CentralizedPrefixProvider shown above, takes a prefix that is
globally prepended to every route. If a particular controller has it’s
own route prefix (obtained via the base.GetRoutePrefix method
invocation), then the centralized prefix is simply prepended to that
one too.
Configure it in the WebAPiConfig like this
config.MapHttpAttributeRoutes(new CentralizedPrefixProvider("api"));
So now for example if you have a controller like this
[RoutePrefix("Test")]
public class TestController : ApiController {
[HttpPost]
[Route("{message}")]
public IHttpActionResult EchoBack(string message) { ... }
}
The above action will be accessed via
<<host>>/api/Test/{message}
where api will be prepended to the controller actions route.

Calling Methods from one API is done but facing Not found error on second API

I have two Wep APIs. I have done CRUD operation using one eg. Customer. But when I built another Similar Web API and called a method It shows:
{,…} Message: "No HTTP resource was found that matches the request URI
http://localhost:23995/Product/Insert'."
MessageDetail: "No route providing a controller name was found to
match request URI '[[same link as above here]]'"
Here is my JS Calling Method:
$scope.Insert = function () {
$http({
method: 'post',
url: 'http://localhost:23995/Product/Insert',
data: JSON.stringify($scope.Product)
}).then(function (response) {
alert("chec");
});
}
In Product Controller
// Insert
[HttpPost]
[Route("{controller}/Insert")]
public string Insert([FromBody] Product newProd) {
newProd.Insert();
return newProd.DbResponse;
}
In supplier Controller
// Insert
[HttpPost]
[Route("{controller}/Insert")]
public string Insert([FromBody] Product newProd) {
newProd.Insert();
return newProd.DbResponse;
}
Assuming you already have attribute routing enabled.
Attribute Routing in ASP.NET Web API 2
To enable attribute routing, call MapHttpAttributeRoutes during
configuration. This extension method is defined in the
System.Web.Http.HttpConfigurationExtensions class.
using System.Web.Http;
namespace WebApplication
{
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
// Web API routes
config.MapHttpAttributeRoutes();
// Other Web API configuration not shown.
}
}
}
and assuming that given the route you are getting the error on
http://localhost:23995/Product/Insert
Your product controller should look something like this.
[RoutePrefix("product")]
public class ProductController : ApiController {
// ... other code removed for brevity
// Insert
// eg: POST /product/insert
[HttpPost]
[Route("insert")]
public string Insert([FromBody] Product newProd) {...}
}
and your supplier controller would look very similar
[RoutePrefix("supplier")]
public class SupplierController : ApiController {
// ... other code removed for brevity
// Insert
// eg: POST /supplier/insert
[HttpPost]
[Route("insert")]
public string Insert([FromBody] Product newProd) {...}
}
you calling JavaScript should then be able to properly call the desired methods
Do you have a controller named "ProductController" with a method named Insert?
Looks like that's all that is missing for you.

Categories