Concepts
Service (Application Service)
In Silky, a service refers to an interface that exposes capabilities to the outside world — analogous to a controller in traditional MVC. An interface is declared as an application service by adding the [ServiceRoute] attribute:
[ServiceRoute]
public interface IOrderAppService
{
Task<GetOrderOutput> GetAsync(long id);
Task<PagedList<GetOrderOutput>> GetPageAsync(PagedRequestDto input);
}
Key service properties:
| Property | Description |
|---|---|
Id | Generated from the interface's fully qualified name |
ServiceDescriptor | Metadata registered to the service registry |
IsLocal | Whether this service has a local implementation in this host |
ServiceType | The Type object of the interface |
ServiceProtocol | The protocol (Rpc / Http / WebSocket) |
ServiceEntries | All service entries (methods) this service exposes |
Service Entry
A service entry corresponds to a single method on an application service — analogous to an Action in MVC. Each method generates one or more service entries depending on its HTTP verb and route configuration.
Key service entry properties:
| Property | Description |
|---|---|
Id | Fully qualified method name + parameter names + HTTP method name |
ServiceId | Id of the parent service |
IsLocal | Whether this entry executes locally |
MethodExecutor | ObjectMethodExecutor for the method (handles sync/async/ValueTask) |
Router | HTTP route template, HTTP method, path, and path parameter extractors |
ParameterDescriptors | Describes each method parameter (name, binding source, type) |
GovernanceOptions | Timeout, retry, circuit breaker, load balancing config for this entry |
ClientFilters | Client-side filters applied when calling this entry remotely |
ServerFilters | Server-side filters applied when executing this entry locally |
ServiceEntryDescriptor | Serializable descriptor registered to the service registry |
Application Service Resolution
Service Manager
DefaultServiceManager (singleton) is responsible for resolving and caching all services. It is constructed by injecting all IServiceProvider implementations (not to be confused with .NET's IServiceProvider):
public class DefaultServiceManager : IServiceManager
{
private IEnumerable<Service> m_localServices;
private IEnumerable<Service> m_allServices;
public DefaultServiceManager(IEnumerable<IServiceProvider> providers)
{
UpdateServices(providers);
}
private void UpdateServices(IEnumerable<IServiceProvider> providers)
{
var allServices = new List<Service>();
foreach (var provider in providers)
{
var services = provider.GetServices();
allServices.AddRange(services);
}
m_allServices = allServices;
m_localServices = allServices.Where(p => p.IsLocal).ToList();
}
}
The default DefaultServiceProvider scans all assemblies for interfaces annotated with [ServiceRoute]. Custom providers can be added by implementing IServiceProvider (Silky's own interface).
Route Template Generation
Route templates follow this pattern by default (when Governance:ApiIsRESTfulStyle is true):
{HttpMethod} /{ServiceRouteTemplate}/{appservice}/{ActionName}
ServiceRouteTemplate: from[ServiceRoute(template: "api/order")]{appservice}: injected from the template variable (defaults to the application name)ActionName: method name with leading HTTP verb stripped (e.g.,GetAsync→info)
HTTP verb inference from method name prefix:
| Prefix | HTTP Method |
|---|---|
Get, Query, Search, Find | GET |
Create, Add, Post | POST |
Update, Edit, Put | PUT |
Delete, Remove | DELETE |
Patch | PATCH |
ServiceKey
When multiple implementations of the same interface exist (multi-tenancy, plugin scenarios), services are differentiated using [ServiceKey]. The caller specifies which implementation to target by setting RpcContext.Attachments["ServiceKey"].
Service Entry Manager
After all services and entries are resolved, they are stored in IServiceEntryManager (singleton), which provides fast lookups by:
- Service entry Id
- HTTP method + path (for gateway routing)
- ServiceKey
