docs/en/framework/api-development/auto-controllers.md
//[doc-seo]
{
"Description": "Learn how to automatically create API controllers in ABP Framework, simplifying your application's REST API setup with minimal configuration."
}
Once you create an application service, you generally want to create an API controller to expose this service as an HTTP (REST) API endpoint. A typical API controller does nothing but redirects method calls to the application service and configures the REST API using attributes like [HttpGet], [HttpPost], [Route]... etc.
ABP can automagically configure your application services as API Controllers by convention. Most of time you don't care about its detailed configuration, but it's possible to fully customize it.
Basic configuration is simple. Just configure AbpAspNetCoreMvcOptions and use ConventionalControllers.Create method as shown below:
[DependsOn(BookStoreApplicationModule)]
public class BookStoreWebModule : AbpModule
{
public override void PreConfigureServices(ServiceConfigurationContext context)
{
PreConfigure<AbpAspNetCoreMvcOptions>(options =>
{
options
.ConventionalControllers
.Create(typeof(BookStoreApplicationModule).Assembly);
});
}
}
This example code configures all the application services in the assembly containing the class BookStoreApplicationModule. The figure below shows the resulting API on the Swagger UI.
Some example method names and the corresponding routes calculated by convention:
| Service Method Name | HTTP Method | Route |
|---|---|---|
| GetAsync(Guid id) | GET | /api/app/book/{id} |
| GetListAsync() | GET | /api/app/book |
| CreateAsync(CreateBookDto input) | POST | /api/app/book |
| UpdateAsync(Guid id, UpdateBookDto input) | PUT | /api/app/book/{id} |
| DeleteAsync(Guid id) | DELETE | /api/app/book/{id} |
| GetEditorsAsync(Guid id) | GET | /api/app/book/{id}/editors |
| CreateEditorAsync(Guid id, BookEditorCreateDto input) | POST | /api/app/book/{id}/editor |
ABP uses a naming convention while determining the HTTP method for a service method (action):
If you need to customize HTTP method for a particular method, then you can use one of the standard ASP.NET Core attributes ([HttpPost], [HttpGet], [HttpPut]... etc.). This requires to add Microsoft.AspNetCore.Mvc.Core nuget package to your project that contains the service.
Route is calculated based on some conventions:
PreConfigure<AbpAspNetCoreMvcOptions>(options =>
{
options.ConventionalControllers
.Create(typeof(BookStoreApplicationModule).Assembly, opts =>
{
opts.RootPath = "volosoft/book-store";
});
});
Then the route for getting a book will be '/api/volosoft/book-store/book/{id}'. This sample uses two-level root path, but you generally use a single level depth.
UrlControllerNameNormalizer option. It's a func delegate which allows you to determine the name per controller/service.UrlActionNameNormalizer option. It's an action delegate that is called for every method.IConventionalRouteBuilder is used to build the route. It is implemented by the ConventionalRouteBuilder by default and works as explained above. You can replace/override this service to customize the route calculation strategy.
The route calculation was different before the version 4.0. It was using camelCase conventions, while the ABP version 4.0+ uses kebab-case. If you use the old route calculation strategy, follow one of the approaches;
UseV3UrlStyle to true in the options of the options.ConventionalControllers.Create(...) method. Example:options.ConventionalControllers
.Create(typeof(BookStoreApplicationModule).Assembly, opts =>
{
opts.UseV3UrlStyle = true;
});
This approach effects only the controllers for the BookStoreApplicationModule.
UseV3UrlStyle to true for the AbpConventionalControllerOptions to set it globally. Example:Configure<AbpConventionalControllerOptions>(options =>
{
options.UseV3UrlStyle = true;
});
Setting it globally effects all the modules in a modular application.
Creating conventional HTTP API controllers are not unique to application services actually.
If a class implements the IRemoteService interface then it's automatically selected to be a conventional API controller. Since application services inherently implement it, they are considered as natural API controllers.
RemoteService attribute can be used to mark a class as a remote service or disable for a particular class that inherently implements the IRemoteService interface. Example:
[RemoteService(IsEnabled = false)] //or simply [RemoteService(false)]
public class PersonAppService : ApplicationService
{
}
You can further filter classes to become an API controller by providing the TypePredicate option:
PreConfigure<AbpAspNetCoreMvcOptions>(options =>
{
options.ConventionalControllers
.Create(typeof(BookStoreApplicationModule).Assembly, opts =>
{
opts.TypePredicate = type => { return true; };
});
});
Instead of returning true for every type, you can check it and return false if you don't want to expose this type as an API controller.
API Exploring a service that makes possible to investigate API structure by the clients. Swagger uses it to create a documentation and test UI for an endpoint.
API Explorer is automatically enabled for conventional HTTP API controllers by default. Use RemoteService attribute to control it per class or method level. Example:
[RemoteService(IsMetadataEnabled = false)]
public class PersonAppService : ApplicationService
{
}
Disabled IsMetadataEnabled which hides this service from API explorer and it will not be discoverable. However, it still can be usable for the clients know the exact API path/route.
In addition to Overriding a Controller, you can also use a completely independent Controller to replace the controller in the framework or module.
They have the same route, but can have different input and output parameters.
The ReplaceControllersAttribute indicates the replaced controller type.
[ReplaceControllers(typeof(AbpApplicationConfigurationController))]
[Area("abp")]
[RemoteService(Name = "abp")]
public class ReplaceBuiltInController : AbpController
{
[HttpGet("api/abp/application-configuration")]
public virtual Task<MyApplicationConfigurationDto> GetAsync(MyApplicationConfigurationRequestOptions options)
{
return Task.FromResult(new MyApplicationConfigurationDto());
}
}
public class MyApplicationConfigurationRequestOptions : ApplicationConfigurationRequestOptions
{
}
public class MyApplicationConfigurationDto : ApplicationConfigurationDto
{
}
Configure ControllersToRemove of AbpAspNetCoreMvcOptions to remove the controllers.
services.Configure<AbpAspNetCoreMvcOptions>(options =>
{
options.ControllersToRemove.Add(typeof(AbpLanguagesController));
});