ABP Framework conventional ("auto API") controllers. ABP turns every
application service in an assembly registered with
options.ConventionalControllers.Create(typeof(XModule).Assembly) into an
MVC controller, so an ABP app has almost no hand-written controllers and
the attribute-routed ASP.NET analyzer sees none of its API.
The route mirrors ABP's ConventionalRouteBuilder:
/api/<rootPath>/<service>[/{id}][/<action>[/{xId}]]
rootPath defaults to app; <service> is the class name minus its
AppService/ApplicationService/Service postfix, kebab-cased; the verb
comes from the method-name prefix (HttpMethodHelper.ConventionalPrefixes)
and whatever is left of the name becomes the <action> segment.
Services in a project no Create call covers are left alone: ABP modules
ship hand-written controllers for their app services, and reporting the
conventional route as well would invent a second, unreachable endpoint.
Constants
ABP_DTO_FIELDS = {"
PagedAndSortedResultRequestDto" => ["
Sorting", "
SkipCount", "
MaxResultCount"] of ::
String, "
ExtensiblePagedAndSortedResultRequestDto" => ["
Sorting", "
SkipCount", "
MaxResultCount"] of ::
String, "
PagedResultRequestDto" => ["
SkipCount", "
MaxResultCount"] of ::
String, "
ExtensiblePagedResultRequestDto" => ["
SkipCount", "
MaxResultCount"] of ::
String, "
LimitedResultRequestDto" => ["
MaxResultCount"] of ::
String, "
EntityDto" => ["
Id"] of ::
String}
Request DTO bases from Volo.Abp.Application.Dtos, which are never in
the scanned project.
CONTROLLER_POSTFIXES = ["
AppService", "
ApplicationService", "
IntegrationService", "
Service"] of ::
StringApplicationService.CommonPostfixes, in ABP's removal order.
CREATE_CALL_RE = /ConventionalControllers\s*\.\s*Create\s*\(\s*typeof\s*\(\s*(?:global::)?(?:\w+\.)*(\w+)\s*\)/
CRUD_BASE_RE = /\b(Crud|ReadOnly|AbstractKeyCrud|AbstractKeyReadOnly)AppService\s*</
CRUD_SHAPES = {3 => {2, nil, 1, 1}, 4 => {2, 3, 1, 1}, 5 => {2, 3, 4, 4}, 6 => {2, 3, 4, 5}, 7 => {3, 4, 5, 6}}
Generic-argument positions per arity: {key, list input, create, update}
(nil list input = ABP's PagedAndSortedResultRequestDto default).
ENUM_DECL_RE = /\benum\s+(\w+)/
HTTP_ATTR_RE = /\bHttp(Get|Post|Put|Delete|Patch|Head|Options)(?:Attribute)?\s*(?:\(\s*@?"([^"]*)")?/
METHOD_RE = /^\s*public\s+(?:(?:virtual|override|async|new|sealed)\s+)*(?!static\b|abstract\b|class\b|record\b|struct\b|interface\b|enum\b|event\b|const\b|delegate\b)(?:[\w<>\[\],.?\s]|\([^()]*\))+?\s+(\w+)\s*(?:<[^()]*>)?\s*\(/
The return type may be a tuple: Task<(int Count, string Name)>.
NO_BODY_VERBS =
Set {"
GET", "
DELETE", "
HEAD", "
TRACE"}
Verbs whose complex parameters ABP does not bind from the body.
NON_ACTION_RE = /\[\s*NonAction\b/
POSITIONAL_RECORD_RE = /\brecord\s+(?:class\s+|struct\s+)?(\w+)\s*\(([^)]*)\)/
PRIMITIVE_TYPES =
Set {"string", "int", "long", "short", "byte", "sbyte", "uint", "ulong", "ushort", "bool", "char", "decimal", "double", "float", "
Guid", "
DateTime", "
DateTimeOffset", "
TimeSpan", "
String", "
Int32", "
Int64", "
Boolean"}
READ_ONLY_SHAPES = {3 => {2, nil}, 4 => {2, 3}, 5 => {3, 4}}
REMOTE_OFF_RE = /\bRemoteService(?:Attribute)?\s*\(\s*(?:isEnabled\s*:\s*)?false\b|\bRemoteService(?:Attribute)?\s*\([^)]*\bIsEnabled\s*=\s*false\b/
ROOT_PATH_RE = /\bRootPath\s*=\s*@?"([^"]*)"/
ROUTE_ATTR_RE = /\bRoute(?:Attribute)?\s*\(\s*@?"([^"]*)"/
SERVICE_INTERFACE_RE = /\AI\w*(?:AppService|ApplicationService)\z/
SERVICE_ROOTS =
Set {"
ApplicationService", "
CrudAppService", "
ReadOnlyAppService", "
AbstractKeyCrudAppService", "
AbstractKeyReadOnlyAppService", "
IApplicationService", "
IRemoteService"}
Framework bases (and the marker interfaces) that make a class an
application service.
SOURCE_GATE = /AppService|ApplicationService|ConventionalControllers|AbpModule/
VERB_PREFIXES = {"
GET" => ["
GetList", "
GetAll", "
Get"] of ::
String, "
PUT" => ["
Put", "
Update"] of ::
String, "
DELETE" => ["
Delete", "
Remove"] of ::
String, "
POST" => ["
Create", "
Add", "
Insert", "
Post"] of ::
String, "
PATCH" => ["
Patch"] of ::
String}
HttpMethodHelper.ConventionalPrefixes; the verb test is a
case-insensitive StartsWith, anything unmatched is POST.
Instance methods
tech
Instance-side view of the same declaration. The per-file rescues live on
this base class, which has no way to name the analyzer that is running
inside them, so a skipped file could not be attributed to a tech.
Deriving it from analyzer_for keeps the name written exactly once.
Source