Skip to content

IAppServices conventional routing

As previously discussed, our Application layer services (henceforth IAppServices) can be used as a presentation layer for HTTP based services.

This dynamic Api Controller's presentation layer integrates seamlessly with ordinary Api Controllers, so developers will always be able to choose the way in which those services will be exposed and consumed, either by using ordinary or dynamic auto-generated Api Controllers.

The mechanism behind which said IAppServices are wired as Controllers is discussed in following sections.

Discovering IAppService implementations

Types implementing IAppService will be discovered, registered in DI, and wired as Api Controllers by the Suite Framework, without any user intervention.

Base route path

The Suite Framework will use the same base route path for all IAppService when building Mvc Routes, said base path can be configured through EndpointsModuleOptions to suite your needs. By default the value is set to api, this means that no matter what your entity name is, it will be routed from that base root path onwards, thus the route built by the Suite Framework will look like 'api/{YOUR_ENTITY}/{ENTITY_METHOD}.

Routing convention

Given an IAppService, the Suite Framework will calculate a valid Mvc Route for every single public method available. Each IAppService's method will be given a name, and an http method (verb) constraint, based on its characteristics. Parameters will also be mapped to QueryString, Route template, Body or Headers following conventions explained more in detail in next sections.

Notice

When more than one method's calculated route collides, the Suite Framework will create a route only mapped to one of the colliding methods. You must be aware of this situation and choose suitable method names that the Suite Framework can use to wire up the IAppService's methods to.

There is a switch in EndpointsModuleOptions that you can use to tell the Suite Framework to stop and fail, in such cases where the conventional routing isn't able to map the public IAppService´s methods to valid Mvc routes. By default the Suite Framework sets the default value to false.

If, for convenience, you want to switch-off the failing behavior, you can manually set it by injecting EndpointsModuleOptions, and configuring the module to suite your purposes.

Taking the following IAppService as an example:

C#
public interface IJobsAppService : IAppService
{
    Task<IEnumerable<IJobData>> GetAllJobsAsync();

    Task<IJobData> GetJobByIdAsync(long jobId);

    Task<IJobData> CreateJobAsync(IJobCreationData creationData);

    Task<IEnumerable<IJobData>> SearchJobsAsync(IJobFilterData filterData);

    Task<IJobData> UpdateJobAsync(long jobId, IJobUpdateData updateData);
}

the convention pipeline will infer the following endpoints:

  • GET rootBasePath/Jobs/AllJobs mapping to GetAllJobsAsync.
  • GET rootBasePath/Jobs/JobById/{jobId} mapping to GetJobByIdAsync.
  • POST rootBasePath/Jobs/CreateJob mapping to CreateJobAsync.
  • POST rootBasePath/Jobs/SearchJobs mapping to SearchJobsAsync.
  • PUT rootBasePath/Jobs/UpdateJob/{jobId} mapping to UpdateJobAsync.

Conventions description

The different methods exposed on your IAppServices will be discovered and wired according to the following conventions.

EntityName convention

The controller is given a name based on the IAppService's name, removing the AppService suffix, if any. The Suite Framework will use this entity name not only to label the controller but also to conform the base path for that entity to be accessed throughout Mvc scaffolding. If the type being mapped is an interface, then the leading "I" letter will also be removed.

Notice

To have a good matching between entity name and 'Api Controller Name' when using Dynamic Api Controller feature it's recommended that application services are named with an AppService suffix.

For example, given the following IAppService:

C#
1
2
3
4
public interface IJobsAppService : IAppService
{
    Task<IEnumerable<IJobData>> GetAllJobsAsync();
}

The Suite Framework will do these actions:

  • Use Jobs as entity name, taking away the leading "I" letter, and trailing "AppService" suffix.
  • Map entity to an Api Controller named Jobs.
  • Use Jobs as the main root path part for the Api Controller routing feature.

HttpMethod convention

Notice

This convention should run pretty early in the convention visitors pipeline.

The HTTPMethod for each member will be assigned mainly based on its name (case insensitive):

  • GET: inferred for methods which name begins with 'Get', 'GetAll' or 'GetList'
  • POST: inferred for methods which name begins with 'Post', 'Create', 'Insert', 'Add'. Additionally, if the method has a complex parameter which is not an special parameter it will also be assigned an HTTPMethod of Post.
  • PUT: inferred for methods which name begins with 'Put' or 'Update'.
  • DELETE: inferred for methods which name begins with 'Delete', 'DeleteMany', or 'Remove'.
  • PATCH: inferred for methods which name begins with 'Patch'.

When not matching rule is found, the 'POST' method will be used as default.

Method name

Each IAppService's method name will be extracted, and sanitized as follows, to conform the Mvc Route:

  • Remove async suffix, if any.
  • Remove verb prefix (Get/Post/Delete), if any.

Please note that should the outcome of the convention applied results in an empty descriptor, the method name without async prefix will be used as outcome.

For example, given the following IAppService:

C#
1
2
3
4
public interface IJobsAppService : IAppService
{
    Task<IEnumerable<IJobData>> GetAllJobsAsync();
}
  • Get prefix will be removed from method name.
  • Async suffix will be removed from method name.

The Mvc Route for that entity's method will be:

  • api/Jobs/AllJobs, using GET http method.

Note that the api route path part correspond to the base root path outlined before.

Parameters convention

Depending on the type and purpose of the parameter, it can be placed as route template tokens, request body, query strings or http headers.

Let's dive into the details of how the Suite Framework builds up the Mvc Routing template addressing the burden of wiring up Mvc Routes binding IAppService's methods.

'Id' parameters convention

If the parameter is named, or ends with "Id", it will be used as part of the template route. For example:

C#
1
2
3
4
public interface IJobsAppService : IAppService
{
    Task<IJobData> GetJobByIdAsync(long jobId);
}

The method GetJobByIdAsync will be reached at the following Mvc Route.

  • GET api/Jobs/JobById/{jobId} mapping to GetJobByIdAsync

Pay attention to the '{jobId}' token in the route template. This is the way the Suite Framework builds the route mapping when an 'Id' parameter is present.

Primitive parameters convention

When a parameter type is primitive, it will be mapped to the QueryString part of the Mvc Routing. The exception of this rule is when the parameter is considered to be an Id parameter, in such cases the convention applied will be the Id parameter one.

For example, given the following IAppService:

C#
1
2
3
4
public interface IJobsAppService : IAppService
{
    Task<IJobData> GetJobByIdAsync(long jobId, string param1, bool param2);
}

The Suite Framework will build up the following Mvc Route:

  • api/Jobs/JobById/{jobId}?param1=SomeValue&param2=true mapping to GetJobByIdAsync, with GET HTTPMethod.

Some things to note here:

  • jobId parameter remains a route element, no matter if it is primitive or not, because it's treated as an Id parameter.
  • param1 and param2 are mapped to the QueryString routing path part.

Complex parameters convention

Note: complex stands for non-primitive types.

When a parameter type is complex, it will be mapped to the Body part of the Mvc Routing and the expected Http method will be changed to Post, regardless of what Verb convention was applied, this condition will overrule any value defined prior by the convention.

For example, given the following IAppService:

C#
1
2
3
4
public interface IJobsAppService : IAppService
{
    Task<IJobData> GetJobBySomeCriteriaAsync(ComplexDTO jobInfo);
}

The Suite Framework will build up the following Mvc Route:

  • api/Jobs/JobBySomeCriteria mapping to GetJobBySomeCriteriaAsync, with POST http method and jobInfo as body parameter.

Please note that even though the IAppService's method could be mapped to GET http verb, given the GET prefix in its name, the method will be mapped to POST http verb, because of the complex param type of jobInfo parameter.

Cancellation token convention

When a method has a parameter of type CancellationToken our conventions will bind and configure MVC routing so that said parameter is router the same way it would if we were using ordinary Api Controllers.

For example, given the following IAppService:

C#
1
2
3
4
public interface IJobsAppService : IAppService
{
    Task<IJobData> GetJobBySomeCriteriaAsync(ComplexDTO jobInfo, CancellationToken ct);
}

The Suite Framework will build up the following Mvc Route:

  • api/Jobs/JobBySomeCriteria mapping to GetJobBySomeCriteriaAsync, with POST http method and jobInfo as body parameter. The Cancellation Token parameter will be handled by MVC and it won't be part of the route or parameters in any way whatsoever