-
Notifications
You must be signed in to change notification settings - Fork 710
Controller Conventions
There are a few implicit conventions to be aware of.
Once you opt into API versioning, every API controller has an API version. This is true even if the controller does not have an explicit attribute or configured convention. When otherwise unspecified, the version applied to a controller derives from ApiVersioningOptions.DefaultApiVersion.
ASP.NET provides a built-in convention for controller names that use the form
[name]Controller
where Controller
will be trimmed off when exactly that text. API
Versioning slightly expands this convention. It will honor the convention of
[name][#]Controller
. This allows you to have two controller types in the same
namespace for different API versions, but for the same resource; for example,
ValuesController
and Values2Controller
will both have the name Values
. Naming
is important for grouping controllers together.
Alternate grouping, such as by route template, is unreliable. For example, the template
api/values/{id}
andapi/values/{id:int}
are semantically equivalent. Understanding that two URLs are not identical, but are semantically equivalent can be complex and requires template parsing to understand them.
.NET only allows a single, unique type name per namespace. You can use the same name by
splitting your controllers into different namespaces. You can also explicitly define
the controller name using the ControllerNameAttribute (ex: [ControllerName("Values")]
).
Applies to ASP.NET Core only
A controller is just a controller in ASP.NET Core; there is no distinction between a UI Controller and an API Controller. Some applications mix UI controllers and API controllers together. This will result in all controllers requiring an API version, which is undesirable for UI controllers. The advent of the ApiControllerAttribute made it possible to disambiguate the two types of controllers.
API Versioning 3.0 introduced two new interfaces:
interface IApiControllerFilter
{
IList<ControllerModel> Apply( IList<ControllerModel> controllers );
}
interface IApiControllerSpecification
{
bool IsSatisifedBy( ControllerModel controller );
}
The IApiControllerFilter filters which controllers should be considered API controllers. The default implementation typically does not need to be replaced.
The IApiControllerSpecification defines a specification as to whether a particular controller is an API controller.
There are two built-in specifications:
-
ApiBehaviorSpecification - matches controllers decorated by
[ApiController]
-
ODataControllerSpecification - matches controllers decorated by
[ODataRouting]
An API controller will be considered any controller that matches at least one specification. If a built-in specification does not meet your specific needs, you can create your own:
// considers controllers inheriting from Controller to be a UI controller
public class NonUIControllerSpecification : IApiControllerSpecification
{
readonly Type UIControllerType = typeof( Controller ).GetTypeInfo();
public bool IsSatisfiedBy( ControllerModel controller ) =>
!UIControllerType.IsAssignableFrom( controller.ControllerType )
}
Register your specification in the services configuration:
services.TryAddEnumerable(
ServiceDescriptor.Transient<IApiControllerSpecification,
NonUIControllerSpecification>() );
To disable this feature, change ApiVersioningOptions.UseApiBehavior to false
.
- Home
- Quick Starts
- Version Format
- Version Discovery
- Version Policies
- How to Version Your Service
- API Versioning with OData
- Configuring Your Application
- Error Responses
- API Documentation
- Extensions and Customizations
- Known Limitations
- FAQ
- Examples