Silky Microservice FrameworkSilky Microservice Framework
Home
Docs
Config
Source
github
gitee
  • 简体中文
  • English
Home
Docs
Config
Source
github
gitee
  • 简体中文
  • English
  • Startup

    • Silky Framework Source Code Analysis
    • Host Construction
    • Service Engine
    • Module System
    • Service & Service Entry Resolution
    • Service Registration
    • Dependency Injection Conventions
    • RPC Service Proxy
  • Runtime

    • Endpoints & Routing
    • Executor Dispatch System
    • Local Executor & Server-Side Filters
    • Remote Executor & RPC Call Chain
    • RPC Server Message Handling
    • Service Governance
    • Cache Interceptor
    • Distributed Transactions (TCC)
    • HTTP Gateway Pipeline
    • Filter Pipeline
    • Polly Resilience Pipeline
    • Endpoint Health Monitor

Overview

Silky uses Autofac as its underlying IoC container. By injecting AutofacServiceProviderFactory into the .NET host, Silky replaces the default IServiceCollection container with Autofac's more powerful DI capabilities.

In addition to the standard IServiceCollection.AddXxx() or explicit Autofac ContainerBuilder registrations, Silky provides a convention-based dependency injection mechanism: implement a marker interface and the framework automatically scans and registers your class at startup — no manual registration code required.


Marker Interfaces

Three marker interfaces correspond to Autofac's three lifecycle scopes:

InterfaceAutofac LifetimeDescription
ITransientDependencyInstancePerDependencyTransient: a new instance per resolution
IScopedDependencyInstancePerLifetimeScopeScoped: one instance per lifetime scope (per request)
ISingletonDependencySingleInstanceSingleton: one instance for the entire application lifetime

Usage

// Transient: new instance every time
public class OrderService : IOrderService, ITransientDependency
{
}

// Scoped: same instance within one request scope
public class CurrentUserContext : ICurrentUserContext, IScopedDependency
{
}

// Singleton: same instance throughout the application
public class LocalServiceEntryManager : IServiceEntryManager, ISingletonDependency
{
}

Auto-Registration Logic (DefaultDependencyRegistrar)

public class DefaultDependencyRegistrar : IDependencyRegistrar
{
    public void Register(ContainerBuilder builder, ITypeFinder typeFinder)
    {
        var refAssemblies = typeFinder.GetAssemblies();
        foreach (var assembly in refAssemblies)
        {
            // Singleton
            builder.RegisterAssemblyTypes(assembly)
                .Where(t => typeof(ISingletonDependency).IsAssignableFrom(t)
                         && !t.GetCustomAttributes().OfType<InjectNamedAttribute>().Any())
                .PropertiesAutowired()
                .AsImplementedInterfaces()
                .AsSelf()
                .SingleInstance();

            // Transient
            builder.RegisterAssemblyTypes(assembly)
                .Where(t => typeof(ITransientDependency).IsAssignableFrom(t)
                         && !t.GetCustomAttributes().OfType<InjectNamedAttribute>().Any())
                .PropertiesAutowired()
                .AsImplementedInterfaces()
                .AsSelf()
                .InstancePerDependency();

            // Scoped
            builder.RegisterAssemblyTypes(assembly)
                .Where(t => typeof(IScopedDependency).IsAssignableFrom(t)
                         && !t.GetCustomAttributes().OfType<InjectNamedAttribute>().Any())
                .PropertiesAutowired()
                .AsImplementedInterfaces()
                .AsSelf()
                .InstancePerLifetimeScope();
        }
    }
}

Key points:

  • All convention-registered types have PropertiesAutowired() enabled — public properties are also injected by Autofac
  • Types marked with [InjectNamed] are excluded from this scan — handled separately by NamedServiceDependencyRegistrar

Property Injection (PropertiesAutowired)

Convention-registered classes can receive dependencies via public property injection, without listing them in the constructor:

public class DefaultServerMessageReceivedHandler : ISingletonDependency
{
    // Property injection: Autofac sets this automatically
    public ILogger<DefaultServerMessageReceivedHandler> Logger { get; set; }

    // Constructor injection still works alongside property injection
    private readonly IServiceEntryLocator _serviceEntryLocator;

    public DefaultServerMessageReceivedHandler(IServiceEntryLocator serviceEntryLocator)
    {
        _serviceEntryLocator = serviceEntryLocator;
    }
}

Named Injection ([InjectNamed])

When multiple implementations of the same interface exist, use [InjectNamed] with a named key to differentiate them:

[InjectNamed("Zookeeper")]
public class ZookeeperRegistryCenter : IRegistryCenter, ISingletonDependency
{
}

[InjectNamed("Consul")]
public class ConsulRegistryCenter : IRegistryCenter, ISingletonDependency
{
}

Resolve by name:

var center = EngineContext.Current.ResolveNamed<IRegistryCenter>("Zookeeper");

Manual Resolution (EngineContext.Current)

For cases where constructor injection is unavailable (e.g., static helpers, factory classes):

// Resolve by type
var executor = EngineContext.Current.Resolve<IExecutor>();

// Resolve named service
var registryCenter = EngineContext.Current.ResolveNamed<IRegistryCenter>("Consul");

// Access the host name
var hostName = EngineContext.Current.HostName;

Warning

Manual resolution via EngineContext.Current bypasses DI lifetime management. Prefer constructor or property injection wherever possible.

Edit this page
Prev
Service Registration
Next
RPC Service Proxy