pub struct ServiceProvider { /* private fields */ }Expand description
Built service provider — the root DI container (read-only after build).
兼具 MEDI 中 IServiceProvider 与 root scope 双重身份:
- 作为
IServiceProvider:提供类型/键控/命名解析入口。 - 作为 root scope:默认启用严格 scope 校验(对齐 MEDI/ASP.NET Core 开发环境的
ValidateScopes),从根解析 Scoped 服务返回RdiError::ScopedFromRootProvider; 在ServiceProvider::scope创建的 Scope 内解析则正常缓存复用。若确实需要 0.7 的“根 scope 内单例化“行为,可用ServiceProviderOptions::lenient+ServiceCollection::build_with。 - 与 MEDI 对齐,容器自身可作为内建服务解析:
provider.get::<ServiceProvider>()与#[inject] Arc<ServiceProvider>(或专用#[inject(provider)])均可用, eager singleton 与懒解析服务一致。 ServiceProvider::dispose按创建逆序释放 singleton / root-scoped 实例并 标记容器不可用(后续解析返回RdiError::ProviderDisposed)。- ⚠️ singleton 持有
Arc<ServiceProvider>会形成容器 → singleton → 容器的 强引用环,容器不再可能被回收;需要按任务创建 scope 的 singleton 应优先注入ScopeFactory(内置实现为弱引用,无环)。构造函数内也不要通过注入的 provider 解析服务(会被拒绝),请保存句柄并在方法中延迟解析。
Analogous to IServiceProvider in MEDI.
Implementations§
Source§impl ServiceProvider
impl ServiceProvider
Sourcepub fn register_disposable(&self, cleanup: Box<dyn FnOnce() + Send>)
pub fn register_disposable(&self, cleanup: Box<dyn FnOnce() + Send>)
Register a cleanup closure for scoped services/owned resources.
Closures run (in reverse registration order) when
Self::dispose is called — either explicitly or by Scope’s
Drop for scope providers.
Sourcepub fn dispose(&self)
pub fn dispose(&self)
Dispose this provider: release cached instances in reverse creation order, run registered cleanups in reverse registration order, and mark the provider unusable.
- Root provider: also marks the whole provider tree disposed (existing scopes can no longer resolve), drains the singleton cache, and clears named registrations. Singleton instances are released in reverse creation order (LIFO), so dependents drop before their dependencies.
- Scope provider: releases the scoped instances created in that scope and runs its cleanups. Singletons are untouched.
Idempotent. Instances are released by dropping the container’s strong
references; a service’s Drop runs when no other owner keeps it alive.
Services obtained via get_owned are caller-owned and are not tracked.
The caller must not resolve services concurrently with disposal (same
contract as MEDI’s ServiceProvider.Dispose). A panicking cleanup closure
does not stop the remaining cleanups; the first panic is re-raised after
disposal (and swallowed when the thread is already unwinding, e.g. during
Scope’s Drop).
Sourcepub fn get<T>(&self) -> Result<Arc<T>, RdiError>
pub fn get<T>(&self) -> Result<Arc<T>, RdiError>
Resolve a service by type. Works uniformly for concrete types and trait objects.
Returns Err(RdiError::ServiceNotFound) if not registered.
ScopeFactory is always available from a built provider (no manual
registration required). An explicit singleton::<dyn ScopeFactory>(...)
registration still takes precedence. Later registrations override earlier
ones (MEDI semantics).
Sourcepub fn get_optional<T>(&self) -> Option<Arc<T>>
pub fn get_optional<T>(&self) -> Option<Arc<T>>
Resolve a service by type, returning None if it is not registered or
not resolvable at this point (e.g. a scoped service under root scope
validation, or a disposed provider). Use Self::get when you need the
concrete error.
Sourcepub fn get_async<T>(
&self,
) -> impl Future<Output = Result<Arc<T>, RdiError>> + Send
pub fn get_async<T>( &self, ) -> impl Future<Output = Result<Arc<T>, RdiError>> + Send
Resolve an async service by type.
The returned future captures the current async resolution chain at
construction time (synchronously), so nested resolution inherits the
chain even when the future is moved to another task. For fully detached
task closures, propagate Self::async_context (see its docs).
Sourcepub fn get_keyed_async<T>(
&self,
key: impl Into<ServiceKey> + Send,
) -> impl Future<Output = Result<Arc<T>, RdiError>> + Send
pub fn get_keyed_async<T>( &self, key: impl Into<ServiceKey> + Send, ) -> impl Future<Output = Result<Arc<T>, RdiError>> + Send
Resolve an async keyed service by type and key.
Accepts string keys and typed ServiceKey values. AnyKey fallback
registrations are synchronous by design and are resolved through the
synchronous keyed path.
Sourcepub fn get_keyed<T>(
&self,
key: impl Into<ServiceKey>,
) -> Result<Arc<T>, RdiError>
pub fn get_keyed<T>( &self, key: impl Into<ServiceKey>, ) -> Result<Arc<T>, RdiError>
Resolve a keyed service by type and key. Resolve a keyed service by type and key.
Accepts string keys ("name") as well as typed ServiceKey values.
Exact-key registrations take precedence; otherwise an AnyKey fallback
registration is used for the requested key.
Returns Err(RdiError::KeyedServiceNotFound) if not found.
Sourcepub fn get_owned<T>(&self) -> Result<T, RdiError>
pub fn get_owned<T>(&self) -> Result<T, RdiError>
Resolve owned T (bypass cache, fresh each call).
Returns Err if not registered or the service is Singleton.
Owned resolution hands the instance to the caller: it is not tracked by
the container and stays valid after dispose. Scoped ownership bypasses
the scope cache, so a root scope-validation error is not raised for the
owned instance itself; its dependencies still obey scope validation.
Sourcepub fn try_get_owned<T>(&self) -> Option<T>
pub fn try_get_owned<T>(&self) -> Option<T>
Resolve owned T, returning None if not registered, a Singleton, or the
provider/scope is disposed.
Sourcepub fn get_keyed_owned<T>(
&self,
key: impl Into<ServiceKey>,
) -> Result<T, RdiError>
pub fn get_keyed_owned<T>( &self, key: impl Into<ServiceKey>, ) -> Result<T, RdiError>
Resolve owned keyed T.
Returns Err if not found or Singleton.
Sourcepub fn try_get_keyed_owned<T>(&self, key: impl Into<ServiceKey>) -> Option<T>
pub fn try_get_keyed_owned<T>(&self, key: impl Into<ServiceKey>) -> Option<T>
Resolve owned keyed T, returning None if not found, a Singleton, or
the provider/scope is disposed.
Sourcepub fn get_all<T>(&self) -> Vec<Arc<T>>
pub fn get_all<T>(&self) -> Vec<Arc<T>>
Return all unkeyed registered instances of the given type, in
registration order (MEDI GetServices<T>() / IEnumerable<T> parity).
Keyed implementations are excluded — use Self::get_all_keyed for
those. Under root scope validation, scoped services are not resolvable at
the root and are omitted; other resolution failures panic with a typed
RdiError payload (mirroring MEDI, where enumeration throws).
Sourcepub fn get_all_keyed<T>(&self) -> Vec<Arc<T>>
pub fn get_all_keyed<T>(&self) -> Vec<Arc<T>>
Return all keyed registered instances of the given type, in
registration order (MEDI GetKeyedServices<T>(KeyedService.AnyKey) parity).
AnyKey fallback registrations are excluded: MEDI’s AnyKey enumeration
returns only registrations with an explicit key.
Sourcepub fn scope(self: &Arc<ServiceProvider>) -> Scope
pub fn scope(self: &Arc<ServiceProvider>) -> Scope
Create a new service scope.
Analogous to IServiceProvider.CreateScope() in MEDI.
Scoped-lifetime services are cached within the returned scope.
Sourcepub fn is_registered<T>(&self) -> bool
pub fn is_registered<T>(&self) -> bool
Whether T has a resolvable registration (or is a built-in container
service). MEDI IServiceProviderIsService parity.
Reports registration state only: it is still true after Self::dispose.
Sourcepub fn is_registered_keyed<T>(&self, key: impl Into<ServiceKey>) -> bool
pub fn is_registered_keyed<T>(&self, key: impl Into<ServiceKey>) -> bool
Whether T has a registration under key (exact key, or an AnyKey
fallback registration). MEDI IServiceProviderIsService.IsKeyedService parity.
Sourcepub fn get_named<T>(&self, name: &str) -> Option<Arc<T>>
pub fn get_named<T>(&self, name: &str) -> Option<Arc<T>>
Cross-DLL safe named service resolution (generic).
Sourcepub fn get_named_any(&self, name: &str) -> Option<Arc<dyn Any + Send + Sync>>
pub fn get_named_any(&self, name: &str) -> Option<Arc<dyn Any + Send + Sync>>
Non-generic named resolution; returns Arc<dyn Any> for trait-object dispatch.
Sourcepub fn register_named<T>(&self, name: &str, service: Arc<T>)
pub fn register_named<T>(&self, name: &str, service: Arc<T>)
Register a named service for cross-DLL plugin access.
No-op after the provider/scope has been disposed (the named registry is
cleared by Self::dispose).
Sourcepub fn remove_named(&self, name: &str)
pub fn remove_named(&self, name: &str)
Remove a named service (for plugin unload).
Sourcepub fn rdi_register_named(
&self,
name: &str,
service: Arc<dyn Any + Send + Sync>,
)
pub fn rdi_register_named( &self, name: &str, service: Arc<dyn Any + Send + Sync>, )
Register a named service (for IProvider trait).
No-op after the provider/scope has been disposed.
Sourcepub fn rdi_remove_named(&self, name: &str)
pub fn rdi_remove_named(&self, name: &str)
Remove a named service (for IProvider trait).
Source§impl ServiceProvider
impl ServiceProvider
Sourcepub fn async_context(&self) -> Option<AsyncFactoryContext>
pub fn async_context(&self) -> Option<AsyncFactoryContext>
Create an AsyncFactoryContext bound to the current async
resolution chain.
Call this inside an async factory (before spawning) to get a handle that
can be cloned into detached tasks. Outside a factory the context starts a
fresh chain. Returns None only for a provider whose self-reference is
not initialized (should not happen for a built provider).
Trait Implementations§
Source§impl DbContextResolver for ServiceProvider
impl DbContextResolver for ServiceProvider
Source§fn get_owned_context(
&self,
key: impl IDbContextKey + Into<ServiceKey>,
) -> Result<DbContext, RdiError>
fn get_owned_context( &self, key: impl IDbContextKey + Into<ServiceKey>, ) -> Result<DbContext, RdiError>
DbContext for key (allowed from the root provider).Source§fn get_context(
&self,
key: impl IDbContextKey + Into<ServiceKey>,
) -> Result<Arc<DbContext>, RdiError>
fn get_context( &self, key: impl IDbContextKey + Into<ServiceKey>, ) -> Result<Arc<DbContext>, RdiError>
Arc<DbContext> for key (requires a scope).Source§impl IProvider for ServiceProvider
impl IProvider for ServiceProvider
Source§impl IServiceResolver for ServiceProvider
impl IServiceResolver for ServiceProvider
Source§fn try_get_any_result(
&self,
key: &str,
) -> Result<Option<Arc<dyn Any + Send + Sync>>, RdiError>
fn try_get_any_result( &self, key: &str, ) -> Result<Option<Arc<dyn Any + Send + Sync>>, RdiError>
Infallible lookup: reports absence instead of panicking for scope
violations / disposal (still returns Err for factory failures so
callers could distinguish, but IServiceResolver::try_get maps it to
None).
Source§fn try_get_keyed_any_result(
&self,
key: &str,
variant: &str,
) -> Result<Option<Arc<dyn Any + Send + Sync>>, RdiError>
fn try_get_keyed_any_result( &self, key: &str, variant: &str, ) -> Result<Option<Arc<dyn Any + Send + Sync>>, RdiError>
Keyed variant of IServiceResolver::try_get_any_result.
fn get_any(&self, key: &str) -> Option<Arc<dyn Any + Send + Sync>>
fn get_keyed_any( &self, key: &str, variant: &str, ) -> Option<Arc<dyn Any + Send + Sync>>
Source§fn get_keyed_any_key(
&self,
key: &str,
variant: &ServiceKey,
) -> Option<Arc<dyn Any + Send + Sync>>
fn get_keyed_any_key( &self, key: &str, variant: &ServiceKey, ) -> Option<Arc<dyn Any + Send + Sync>>
#[inject(key = <expr>)]). Read moreSource§fn try_get_keyed_any_result_key(
&self,
key: &str,
variant: &ServiceKey,
) -> Result<Option<Arc<dyn Any + Send + Sync>>, RdiError>
fn try_get_keyed_any_result_key( &self, key: &str, variant: &ServiceKey, ) -> Result<Option<Arc<dyn Any + Send + Sync>>, RdiError>
Self::get_keyed_any_key.Source§fn get_keyed_owned_any_key(
&self,
key: &str,
variant: &ServiceKey,
) -> Option<Arc<dyn Any + Send + Sync>>
fn get_keyed_owned_any_key( &self, key: &str, variant: &ServiceKey, ) -> Option<Arc<dyn Any + Send + Sync>>
Source§fn try_get_keyed_owned_any_key(
&self,
key: &str,
variant: &ServiceKey,
) -> Result<Option<Arc<dyn Any + Send + Sync>>, RdiError>
fn try_get_keyed_owned_any_key( &self, key: &str, variant: &ServiceKey, ) -> Result<Option<Arc<dyn Any + Send + Sync>>, RdiError>
Self::get_keyed_owned_any_key.Source§fn get_keyed_by_type_id(
&self,
tid: TypeId,
key: &str,
) -> Option<Arc<dyn Any + Send + Sync>>
fn get_keyed_by_type_id( &self, tid: TypeId, key: &str, ) -> Option<Arc<dyn Any + Send + Sync>>
None)。 Read moreSource§fn get_all_any(&self, key: &str) -> Vec<Arc<dyn Any + Send + Sync>>
fn get_all_any(&self, key: &str) -> Vec<Arc<dyn Any + Send + Sync>>
Source§fn get_all_keyed_any(&self, key: &str) -> Vec<Arc<dyn Any + Send + Sync>>
fn get_all_keyed_any(&self, key: &str) -> Vec<Arc<dyn Any + Send + Sync>>
GetKeyedServices<T>(KeyedService.AnyKey)). Read moreSource§fn get_all_any_result(
&self,
key: &str,
) -> Result<Vec<Arc<dyn Any + Send + Sync>>, RdiError>
fn get_all_any_result( &self, key: &str, ) -> Result<Vec<Arc<dyn Any + Send + Sync>>, RdiError>
Self::get_all_any, used by the inject
macros for Vec<Arc<T>> fields. Read moreSource§fn get_owned_any(&self, key: &str) -> Option<Arc<dyn Any + Send + Sync>>
fn get_owned_any(&self, key: &str) -> Option<Arc<dyn Any + Send + Sync>>
Arc<dyn Any + Send + Sync> (concrete Arc<Arc<T>>). Read morefn get_keyed_owned_any( &self, key: &str, variant: &str, ) -> Option<Arc<dyn Any + Send + Sync>>
Source§fn provider_arc(&self) -> Option<Arc<ServiceProvider>>
fn provider_arc(&self) -> Option<Arc<ServiceProvider>>
Arc<ServiceProvider> for on-demand service resolution. Read moreSource§fn get<T>(&self) -> Result<Arc<T>, RdiError>
fn get<T>(&self) -> Result<Arc<T>, RdiError>
dyn Trait).
Returns Err(RdiError::ServiceNotFound) if not registered. Read moreSource§fn try_get<T>(&self) -> Option<Arc<T>>
fn try_get<T>(&self) -> Option<Arc<T>>
None if it is not registered or
not resolvable at this point (e.g. a scoped service under root scope
validation, or a disposed provider/scope). Read moreSource§fn get_keyed<T>(&self, variant: &str) -> Result<Arc<T>, RdiError>
fn get_keyed<T>(&self, variant: &str) -> Result<Arc<T>, RdiError>
Err if not found.Source§fn try_get_keyed<T>(&self, variant: &str) -> Option<Arc<T>>
fn try_get_keyed<T>(&self, variant: &str) -> Option<Arc<T>>
None if not found or
not resolvable at this point (e.g. root scope validation, disposed
provider/scope). Never panics for framework-level failures.Source§fn get_all<T>(&self) -> Vec<Arc<T>>
fn get_all<T>(&self) -> Vec<Arc<T>>
T, in registration
order. Read moreSource§fn get_owned<T>(&self) -> Result<T, RdiError>
fn get_owned<T>(&self) -> Result<T, RdiError>
T (bypass cache, fresh each call).
Returns Err if not registered or the service is Singleton.Source§fn try_get_owned<T>(&self) -> Option<T>
fn try_get_owned<T>(&self) -> Option<T>
T, returning None if not registered or Singleton.