Files
DP44/enriched-qwen3-coder-next/Common/DTS.Common.Core/ServiceManager.md
2026-04-17 14:55:32 -04:00

6.3 KiB

source_files, generated_at, model, schema_version, sha256
source_files generated_at model schema_version sha256
Common/DTS.Common.Core/ServiceManager/IServicePublishedEvent.cs
Common/DTS.Common.Core/ServiceManager/ServicePublishedEvent.cs
Common/DTS.Common.Core/ServiceManager/ServiceManager.cs
2026-04-16T02:06:21.064356+00:00 Qwen/Qwen3-Coder-Next-FP8 1 a01f75e5b963dd9f

ServiceManager

Documentation: ServiceManager Module

1. Purpose

The ServiceManager module provides a centralized registry for singleton service implementations, enabling decoupled service discovery and lifecycle management. Components can publish implementations of service interfaces (e.g., IMyService) and other components can retrieve them by interface type without knowledge of the concrete publisher. It also emits IServicePublishedEvent notifications via EventManager whenever services are published or unpublished, supporting reactive integration patterns.


2. Public Interface

ServiceManager (static class)

  • void Publish<T>(T item) where T : class
    Publishes a singleton service implementation item for interface type T. Throws ArgumentException if T is already published. Fires a ServicePublishedEvent with IsPublished = true.

  • void Publish(object item, IEnumerable<Type> interfaceList, bool skipPublishedInterfaces)
    Publishes item for each interface type in interfaceList. If skipPublishedInterfaces is false, throws ArgumentException on encountering an already-published interface; otherwise, skips it. Fires ServicePublishedEvent for newly published interfaces.

  • bool Exists<T>() where T : class
    Returns true if interface type T has a published service; false otherwise.

  • bool Exists(Type t)
    Returns true if interface type t has a published service; false otherwise.

  • T Get<T>() where T : class
    Returns the published service instance for interface type T. Throws ArgumentException if T is not published.

  • void Clear<T>() where T : class
    Unpublishes the service for interface type T. Fires a ServicePublishedEvent with IsPublished = false before removal. No-op if T is not published.

  • void Clear(IEnumerable<Type> interfaceList)
    Unpublishes services for all interface types in interfaceList. Fires ServicePublishedEvent with IsPublished = false for each successfully removed service.

IServicePublishedEvent (interface)

  • Type ServiceType { get; }
    Read-only property returning the Type of the service interface being published/unpublished.

  • bool IsPublished { get; }
    Read-only property: true if the event indicates publication; false if unpublishing.

ServicePublishedEvent (class)

  • Type ServiceType { get; internal set; }
    Gets or sets (internally) the service interface Type.

  • bool IsPublished { get; internal set; }
    Gets or sets (internally) the publication status.


3. Invariants

  • Uniqueness per interface: Each interface type T may have at most one published service instance. Attempting to publish a second implementation for the same interface throws ArgumentException (unless skipPublishedInterfaces = true in the bulk Publish overload).
  • Consistency of Exists/Get/Clear: Exists<T>() and Exists(Type) return true if and only if Services.ContainsKey(typeof(T)) is true. Get<T>() will throw if Exists<T>() is false.
  • Event emission order: For Publish/Clear operations, the ServicePublishedEvent is fired before the service is added/removed from the internal dictionary. Specifically:
    • PublishServices.Add(...)SendServicePublishedEvent(...)
    • ClearSendServicePublishedEvent(...)Services.Remove(...)
  • No null services: The Services dictionary stores only non-null references. Publish accepts any class, but the dictionary does not explicitly validate non-nullability beyond standard dictionary behavior.

4. Dependencies

  • Internal dependencies:

    • System.Collections.Generic.Dictionary<Type, object> for service storage.
    • EventManager.EventManager (from DTS.Common.Core namespace) to publish IServicePublishedEvent instances via EventManager.EventManager.Publish<IServicePublishedEvent>(...).
  • External dependencies:

    • System (for Type, ArgumentException, IEnumerable<T>, etc.).
  • Depended upon by:

    • Any component requiring service discovery (e.g., via ServiceManager.Get<T>()).
    • Event subscribers listening for IServicePublishedEvent to react to service lifecycle changes.

5. Gotchas

  • No thread-safety guarantees: The Services dictionary is not thread-safe. Concurrent Publish/Clear/Get calls may cause race conditions or exceptions (e.g., InvalidOperationException during enumeration or dictionary mutation).
  • Publish(object, ...) allows multiple interfaces per instance: The same object instance may be published under multiple interface types, but this is not validated beyond the existence check per interface.
  • Get<T>() uses as T cast: If the stored object is not actually assignable to T (e.g., due to type mismatch or casting issues), Get<T>() returns null without throwing—but only if the key exists. However, the current implementation first checks ContainsKey, so null return is impossible if the stored object is non-null and correctly typed. If the stored object is null, ContainsKey would still be true, and Get<T>() would return null. This edge case is not explicitly guarded against.
  • Event emission timing: Subscribers receive ServicePublishedEvent before the service is available (for Publish) or after it is removed (for Clear). This may cause race conditions if subscribers immediately call Get<T>()—they will succeed for Publish, but fail for Clear.
  • No support for service versioning or replacement: Once published, a service cannot be replaced without explicit Clear<T>() followed by Publish<T>().
  • internal set on ServicePublishedEvent properties: While the properties are public, their setters are internal, meaning only code within the same assembly can construct/modify ServicePublishedEvent instances. This is consistent with the design but limits extensibility.

None identified beyond the above.