Using WebApi RoutePrefix attribute on a base controller - c#

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

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.

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

MVC trying to do a Get request

I am trying to do a GET request on MVC 4.0 (WebServiceREST) that some method use POST and other use GET but I cant make it works
I used [System.Web.Mvc.AcceptVerbs(HttpVerbs.Get)] but It didnt work still getting "The requested resource does not support the HTTP 'GET' method"
My Controller:
public class RecuperarDatosAppController : ApiController
{
#region RecuperarClasesColectivas
[System.Web.Mvc.AcceptVerbs(HttpVerbs.Get)]
[ResponseType(typeof(List<ActividadesColectivas>))]
public IHttpActionResult RecuperarClasesColectivas(short idInstalacion, string secretKey = "NOSECRETKEY")
{
BsSecurity bSecurity = new BsSecurity(BsSecurity.Tipo.Publica);
if (bSecurity.comprobar(secretKey))
{
BsActividadesColectivas bsActividades = new BsActividadesColectivas();
return Ok(bsActividades.GetActividadesColectivas(idInstalacion));
}
return NotFound();
}
#endregion
}
Though you state this is MVC and tagged it as such, it's actually Web API, because you're inheriting from ApiController. So you should decorate the method with the [HttpGet] attribute from the System.Web.Http namespace. Note that renaming it to have Get prepended like Yoink is suggesting isn't necessary, although that is the common convention.
I believe you need to prepend "Get" to methods that you wish to expose by by GET requests.
So try GetRecuperarClasesColectivas instead of RecuperarClasesColectivas.
You'll still call it by /api/RecuperarClasesColectivas/id for example, the routing just needs the "Get" part adding.

Web API 2.2 return custom 404 when resource (url) not found

I want to be able to take over the 404 response from web api (iis) when the resource does not exist.
I have done my research and came across only one solution that made this work, but i am not sure how "safe" it is since the "routeTemplate" is just {*url}
This post is kinda to ask for help and explanation.
My App uses MVC and WebAPI... would this template affect MVC as well?
Is there a way to add "api" with {*url} in the template? (to make sure only requests with ".../api/..." get affected)
config.Routes.MapHttpRoute("Error404", "{*url}", new { controller = "Error", action = "Handle404" });
Has anyone come across a cleaner way of doing this and handling 404 in web api?
EDIT 1
The above code DOES affect my MVC routes.
How can i add "api" to "{*url}"?... if tried many different ways and no dice.
Had the exact same issue. After some research and trial and error, I was able to find a working solution.
I went with a RoutePrefix solution and I tried to implement something similar to how the MVC controllers used HandleUnknownAction in a base controller.
With the help from this post: .NET WebAPI Attribute Routing and inheritance to allow for route inheritance, I created a base controller for my web APIs with a HandleUnknownAction method like this:
public abstract class WebApiControllerBase : ApiController {
[Route("{*actionName}")]
[AcceptVerbs("GET", "POST", "PUT", "DELETE")]//Include what ever methods you want to handle
[AllowAnonymous]//So I can use it on authenticated controllers
[ApiExplorerSettings(IgnoreApi = true)]//To hide this method from helpers
public virtual HttpResponseMessage HandleUnknownAction(string actionName) {
var status = HttpStatusCode.NotFound;
//This is custom code to create my response content
//....
var message = status.ToString().FormatCamelCase();
var content = DependencyService
.Get<IResponseEnvelopeFactory>()
.CreateWithOnlyMetadata(status, message);
//....
return Request.CreateResponse(status, content);
}
}
If you don't want to go down the inheritance path, you can always put the method directly into the controller you want to apply the functionality on.
This allows me to use route prefixes that handle custom not found messages that pertain to specific controllers as I have both back-office and public public facing APIs.
If a URL does not apply to an ApiController the default Error controller will handle the not found as usual.

Attribute routing not working

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?

Categories