Attribute routing not working - c#

I'm new with attribute routing with aspnet web api.
public class UsersController : ApiController
{
[GET("users/me/brands/{id}")]
public IEnumerable<Brand> GetBrands(long id)
{
return _repository.FindByUser(id);
}
}
but I could not reach this action. I've tried so many ways:
http://example.com/api/users/brands/4
http://example.com/api/users/brands?id=4
http://example.com/users/brands?id=4
http://example.com/users/brands/4
PS: I also mapped as [GET("api/users/me/brands/{id}")]
What I'm missing?

There is a bug in the web api routing with MVC 4 and 4.5
A full explanation and work around can be found
MVC 4.5 Web API Routing not working?

Related

ASP.NET Core API version

I'm trying to create API with ASP.NET Core and their version. I installed Microsoft.AspNetCore.Mvc.Versioning. What I like to have is all the API with the version in the URL, so it is easy to understand what version of the API I use. For example /api/v1/TableAzureCategory.
For thata, in my Startup.cs I added the following lines of code:
services.AddApiVersioning(config =>
{
config.DefaultApiVersion = new ApiVersion(1, 0);
config.AssumeDefaultVersionWhenUnspecified = true;
config.ReportApiVersions = true;
config.ApiVersionReader = new UrlSegmentApiVersionReader();
});
Then, in my API controller I added some decorations
[ApiController]
[ApiVersion("1.0")]
[Route("api/v{version:apiVersion}/[controller]")]
public class TableAzureCategoryController : ControllerBase
{
}
I run the application, open Swagger and this is what I see (basically the {version:apiVersion} is not replaced with the API version)
I looked around but I found only implementation like mine above. Any ideas?
Another way of achieving this would be to create a query-based versioning solution.
Let's say we have two controllers: ExampleV1Controller and ExampleV2Controller
using Microsoft.AspNetCore.Mvc;
namespace MyAPI.Controllers
{
[ApiController]
[ApiVersion("1.0")]
[Route("api/example")]
public class ExampleV1Controller : ControllerBase
{
[HttpGet]
public IActionResult Get()
{
return new OkObjectResult("Example API v1");
}
}
[ApiController]
[ApiVersion("2.0")]
[Route("api/example")]
public class ExampleV2Controller : ControllerBase
{
[HttpGet]
public IActionResult Get()
{
return new OkObjectResult("Example API v2");
}
}
}
As by your Startup.cs configuration, it will default to API version 1.0. To make a request to the V2 version, use https://localhost:5001/api/example?api-version=2.0.
I did not test this myself, but it should work.
The {version} route parameter behaves just like any other route parameter. If the route was values/{id}/subvalues you would expect a parameter named id that must be filled in.
The API Explorer extensions for API Versioning know the version associated with an API. This value is used as the default value, but OpenAPI/Swagger generators (ex: Swashbuckle) may not use the default value without a little help (refer to the end-to-end Swagger Example). If, and only if, you are versioning by URL segment, you can have the API Explorer extensions expand the route template with the default value and remove the API version parameter using the configuration:
services.AddVersionedApiExplorer(options => options.SubstituteApiVersionInUrl = true);
In the example provided, the version route parameter will be removed and the route template will be updated to "api/v1.0/TableAzureCategory", which I presume is what you want.

AspNetCore 3.1 routing AmbiguousMatchException

I am trying to migrate my webapp from .net core 2.1 to 3.1 and in the process changed the routing to app.UseRouting() and app.UseEndpoints(default endpoint) method and removed app.UseMvc() as mentioned in the breaking changes document.
https://learn.microsoft.com/en-us/dotnet/core/compatibility/2.2-3.1#shared-framework-removed-microsoftaspnetcoreall
Post that, facing this issue.
Details
I have 3 controllers mentioned below in the code which are correctly versioned using the attributes
Example of V2 Controller
[Microsoft.AspNetCore.Mvc.ApiVersion("2.0")]
[Route("v{version:apiVersion}")]
Controllers have similar actions methods and when I try to hit any action (example: http://localhost:xxxx/v1/GetData). I get the below exception.
Microsoft.AspNetCore.Routing.Matching.AmbiguousMatchException: 'The request matched multiple endpoints. Matches:
Stateless1.Controllers.V3.SAPClientV3Controller.GetSap (SampleWebApp)
Stateless1.Controllers.V2.SAPClientV2Controller.GetSap (SampleWebApp)
Stateless1.Controllers.V1.SAPClientController.GetSap
PS: I have tested by removing this action method in rest of the two controllers and the call got through to the other controller irrespective of v1 or v2 or v3 in the http://localhost:xxxx/v1/GetData URL.
The code which supports multiple api versioning is also present in the start up.
services.AddApiVersioning((o) =>
{
o.ReportApiVersions = true;
o.DefaultApiVersion = new AspNetCore.Mvc.ApiVersion(1, 0);
o.AssumeDefaultVersionWhenUnspecified = true;
});
I had the exact same issue, and I found this ticket in microsoft's github issues https://github.com/microsoft/aspnet-api-versioning/issues/574
We need to specify the [ApiController] parameter so that the API versioning kicks in. This only started to happen when I migrated from dotnet core 2.0 to 3.1
For clarity here is what works:
[ApiController]
[ApiVersion("1.0")]
[Route("api/v{version:apiVersion}/[controller]")]
public class MyController : Controller
{
[MapToApiVersion("1.0")]
public async Task<IActionResult> MethodA([FromBody] int? id)
{
return Ok();
}
}
}
[ApiController]
[ApiVersion("2.0")]
[Route("api/v{version:apiVersion}/[controller]")]
public class MyControllerV2 : Controller
{
[MapToApiVersion("2.0")]
public async Task<IActionResult> MethodAV2([FromBody] int? id)
{
return Ok();
}
}
}
I gave V2 names for the sake of the example, but I believe the best way to version is to use it with namespaces like V2.Home.MyController

REST API not returning expected results

I'm trying to follow the article Build RESTful API's with ASP.NET Web API to learn how to create a RESTful API.
I created the first project and controller, Contact.
public class ContactController : Controller
{
// GET: Contact
public string[] Index()
{
return new string[]
{
"Hello",
"World"
};
}
}
But when I load the URL in a browser, instead of getting the response described in the article (["Hello","World"]). The response I get is System.String[].
I don't understand what I'm missing.
BTW, the article is from 2013. Does anyone know of a good article that is perhaps a little newer?
What you have now is simple ASP.NET MVC controller. For Web API controller you should inherit your controller from ApiController instead of Controller:
public class ContactController : ApiController
Also action names should start with HTTP verb. If you'll send GET request to /api/contact endpoint you'll get error
The requested resource does not support http method 'GET'.
By default action name is not used in route for Web API controllers. If you'll check default route configuration, it will be api/{controller}/id. Correct action is selected via HTTP method of request. In your case it should be GetXXX or simply Get
You cannot Return regular primitives from the Web Apis. At least if not if you are using a regular MVC Web API from .net. So, if this is the case you could do something like
public class ContactController : Controller
{
// GET: Contact
public JsonResult Index()
{
return Json(new { value1: "Hello", value2: "world" }, JsonRequestBehavior.AllowGet);
}
}
Hope this helps

How do override ASP.NET Core's controller naming convention?

I'm using ASP.NET Core. The convention is that the routing system considers a FooController class to be a controller with the name Foo.
I need to override this convention. I want to do something like this:
[ControllerName("Bar")]
public class SomeArbitraryName : Controller {
}
Or like this:
public class SomeArbitraryName : Controller("Bar") {
}
Is that possible somehow?
EDIT: No that linked "duplicate" question is not for ASP.NET Core!
Attribute routing still exists in Asp.Net Core
[Route("Bar")]
public class SomeArbitraryName : Controller
{
// ...
}
See Documentation: Routing to Controller Actions - Attribute Routing
You could implement your own System.Web.Mvc.IControllerFactory and do ControllerBuilder.Current.SetControllerFactory(new MyImpl()) at some point in the application initialization step
Edit: This advice applies to ASP.NET MVC 5 and Core might have different interfaces for something similar

Using WebApi RoutePrefix attribute on a base controller

I would like all controllers which inherit from AdminBaseApiController to be prefixed with 'admin'.
This works fine of course:
[RoutePrefix("admin")]
public class ToggleController : AdminBaseApiController
{
[Route("toggle")]
public HttpResponseMessage Get()
{
}
}
However when I move the RoutePrefix("admin") out of the ToggleController and into the AdminBaseApiController (where I want it) - The route fails and I get a 404.
Am I looking at this all wrong? Thanks in advance!
Support for inheritance has been enabled in Web API 2.2 release...You can take a look at an example in the following Release Notes:
http://www.asp.net/web-api/overview/releases/whats-new-in-aspnet-web-api-22#ARI

Categories