ASP.NET Core API version - c#

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.

Related

Is there an OOTB component to get routes from controller names and their methods?

I would like to list all the available endpoints a controller provides.
Is it possible to access the component(s) .NET uses to generate these routes (by, for instance providing it a type or controller name (string))?
The methods/verbs (so, POST, GET) are not even that important for my scenario, just the routes themselves.
Example
Please, take a look on the below ASP.NET Core code.
[ApiController]
[Route("[controller]")
public class HomeController : ControllerBase
{
[HttpGet("additional")]
public async Task<IActionResult> Whatever()
{
// ...
}
}
So, the method will be exposed as a GET endpoint on the URL of Home/additional.

Areas do not work when migrating an Angular app to NET 6

I have an .NET Core 5 with Angular app and I have my controllers grouped in areas. I made the app using NET Core 1 and have successfully migrated it up to 5 without any problems, but migrating it to NET 6 gives me a 404 errors when I make API calls.
My current NET 5 setup looks like this:
[Authorize]
[ApiController]
[Route("[area]/[controller]/[action]")]
public abstract class BaseController : Controller
{
}
[Area("Home")]
public abstract class HomeController : BaseController
{
}
public class AccountController : HomeController
{
[HttpGet]
public async Task<IActionResult> GetSomething()
{
}
I created a new project in VS2022, copied everything, made the changes in Program.cs and changed BaseController to inherit ControllerBase.
The angular app works OK, but all my API calls return 404.
I didn't even have this in the NET 5 app, but I added it now just in case:
app.UseEndpoints(endpoints =>
{
endpoints.MapControllerRoute(
name : "areas",
pattern : "{area:exists}/{controller=Home}/{action=Index}/{id?}"
);
});
but still no luck.
EDIT:
Using this answer, I listed all the routes and do get this:
{area: 'Home', controller: 'Account', action: 'GetSomething', name: null, template: 'Home/Account/GetSomething'}
and I still have no idea why it doesn't work.
Because of the proxy you have to list all the areas PROXY_CONFIG in proxy.conf.js. Add the area, or if you're using controllers, the controller names to the context property, eg:
context: ['/AdminApi', '/HomeApi' ... ]
Or, as a workaround, add /Api before all your calls and then have just that in the proxy settings

Controller route not found if it contains a version

I am having issues when trying to route to a Controller when it is included via a external project. The controller in question works fine when included directly in the project or from the external project ONLY when the version field is removed from the route. The controller is defined as below.
[ApiController]
[ApiVersion("1.0")]
[Produces("application/json")]
[Route("api/v{version:apiVersion}/devices")]
[Authorize(Roles = UserConst.PermissionGroup.Admin)]
public class DeviceManagementController : ControllerBase{...}
Changing the route to the below works correctly
[Route("api/devices")]
Changing the route to the below fails the same way as including it through {version:apiVersion}
[Route("api/v1.0/devices")]
Any ideas on what could be wrong? With any version info the server just seems to return the default Index page which is the fallback when a controller cannot be found.
Startup.cs code for adding Api versioning
services.AddApiVersioning(config =>
{
config.DefaultApiVersion =
new ApiVersion(1, 0);
config.AssumeDefaultVersionWhenUnspecified = true;
config.ReportApiVersions = true;
});
I've done some testing.
Af first I added [Route("api/devices")] to your controller attributes
[ApiController]
[ApiVersion("1.0")]
[Produces("application/json")]
[Route("api/v{version:apiVersion}/devices")]
[Route("api/devices")]
public class DeviceManagementController : ControllerBase
and found that url .../api/v1.0/devices works properly.
After this I tryed to use just .../api/devices url.
It was working properly with [ApiVersion("1.0")] attribute
It issued a wrong version error when I changed attribute to [ApiVersion("2.0")]
so everything was working as it was expected.
Summary:
I recommend you to add [Route("api/devices")] and try to use.../api/devices url as a workaround for now, till you find out something better.

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

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