InterfaceFactory 0.1.3

There is a newer version of this package available.
See the version list below for details.
dotnet add package InterfaceFactory --version 0.1.3
                    
NuGet\Install-Package InterfaceFactory -Version 0.1.3
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="InterfaceFactory" Version="0.1.3" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="InterfaceFactory" Version="0.1.3" />
                    
Directory.Packages.props
<PackageReference Include="InterfaceFactory" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add InterfaceFactory --version 0.1.3
                    
#r "nuget: InterfaceFactory, 0.1.3"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package InterfaceFactory@0.1.3
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=InterfaceFactory&version=0.1.3
                    
Install as a Cake Addin
#tool nuget:?package=InterfaceFactory&version=0.1.3
                    
Install as a Cake Tool

InterfaceFactory

InterfaceFactory is a modular library designed to simplify service registration and resolution using a dependency injection (DI) container. This project leverages the power of default implementations in interfaces to provide a clean, centralized, and container-agnostic interface—while still respecting core software architecture principles.


Table of Contents


Overview

InterfaceFactory aims to streamline the process of registering and resolving services within an application. By introducing a set of abstraction layers and default implementations via interfaces (notably through IFactory<T>), it provides an easy-to-use API for service retrieval without sacrificing type safety or architectural clarity.

Key aspects include:

  • Automatic Service Registration: Scans assemblies for implementations of interfaces conforming to specified contracts (using the ContainerRegistration attribute) and registers them with appropriate lifetimes.
  • Centralized DI Integration: Encapsulates the DI container within a central adapter, making it simple to swap out underlying implementations if needed.
  • Default Interface Implementations: Provides default methods within factory interfaces that delegate service resolution requests directly to the DI container.

Features

  • Dynamic Assembly Scanning: Automatically detects and registers services by scanning loaded (and optionally unloaded) assemblies.
  • Flexible Service Lifetimes: Supports Singleton, Scoped, and Transient lifetimes via the ServiceLifetime enumeration.
  • Keyed Registrations: Enables associating services with keys to distinguish between multiple implementations of the same interface.
  • Unified Service Resolution: Default implementations in IFactory<T> allow for a unified, container-agnostic method of accessing services.

Architecture

The project is structured around a few core components:

  1. ContainerRegistrationAttribute & ServiceLifetime

    • These define configuration metadata for service registration.
    • The attribute accepts an optional key and the desired lifetime, ensuring that each service is registered with the correct scope.
  2. IContainerAdapter & ContainerAdapterContainer

    • IContainerAdapter abstracts the underlying DI container operations such as registration and resolution.
    • ContainerAdapterContainer is a static holder that manages the current DI adapter instance.
  3. IFactory<T>

    • Acts as both a contract and a gateway for resolving services.
    • Default methods like GetInstance() and GetRequiredInstance() delegate resolution requests to the central container adapter, ensuring that the business logic remains completely decoupled from the DI setup.
  4. Container Registration Mechanism

    • Scans and registers all matching service interfaces automatically.
    • Integration with the Microsoft.Extensions.DependencyInjection container is provided via extension methods, ensuring seamless DI container registration and usage.

Getting Started

To integrate InterfaceFactory into your project:

  1. Install the provided NuGet packages.
  2. Register services with your DI container by extending your ServiceCollection using:
    serviceCollection.RegisterInterfaceFactories(includeUnloadedAssemblies: true);
    
  3. Once the ServiceProvider is built, set it by calling:
    serviceProvider.UseInterfaceFactory();
    
  4. Retrieve services through the default methods in IFactory<T>, e.g.:
    var myService = IExample.GetInstance();
    var myKeyedService = IExample.GetRequiredKeyedInstance("MyServiceKey");
    

Usage Examples

Example 1: Basic Service Resolution

public interface IExample : IFactory<IExample> { }

[ContainerRegistration(ServiceLifetime.Scoped, "MyExample")]
public class MyExample : IExample { }

// Service registration and usage:
ServiceCollection serviceCollection = new();
serviceCollection.RegisterInterfaceFactories(includeUnloadedAssemblies: true);
IServiceProvider serviceProvider = serviceCollection.BuildServiceProvider();
serviceProvider.UseInterfaceFactory();

IExample? instance = IExample.GetInstance();
IExample requiredInstance = IExample.GetRequiredKeyedInstance("MyExample");

Example 2: Multiple Implementations

public interface IReport : IFactory<IReport> { }

[ContainerRegistration(ServiceLifetime.Transient, "SimpleReport")]
public class SimpleReport : IReport { }

[ContainerRegistration(ServiceLifetime.Transient, "DetailedReport")]
public class DetailedReport : IReport { }

// Retrieve specific implementation by key:
IReport simpleReport = IReport.GetRequiredKeyedInstance("SimpleReport");
IReport detailedReport = IReport.GetRequiredKeyedInstance("DetailedReport");

Default Implementations & Software Architecture

Addressing Architectural Concerns

Default implementations in interfaces have often been criticized for several reasons:

  • Blurring of Responsibility: Critics argue that default logic in an interface can mix contract definition with implementation details.
  • Potential for Naming Conflicts: Multiple inheritance-like issues might arise if two interfaces provide default implementations for the same members.
  • Hidden Dependencies: Developers might not notice that default code introduces hidden dependencies or side effects.
  • Testability Challenges: The embedded logic might complicate the unit testing of components using such interfaces.

How InterfaceFactory Mitigates These Concerns

In InterfaceFactory, the default implementations in IFactory<T> are intentionally kept minimalistic and serve only as a direct delegation mechanism. They provide a clear and declarative way to access services from the central DI container without introducing any business logic or hidden side effects.

Clear Separation of Concerns
  • Interface as a Contract: The IFactory<T> interface strictly serves as a contract for service retrieval. The default methods (GetInstance(), GetRequiredInstance(), etc.) do not contain complex logic; they simply delegate to the central container adapter.
  • Centralized Logic: All actual service resolution and DI-related logic is encapsulated within the ContainerAdapter. This keeps the interface free from domain-specific dependencies.
Avoiding Naming Conflicts
  • Explicit Calling Convention: Default methods are invoked statically (e.g., IExample.GetInstance()), which avoids issues related to multiple inheritances seen in instance method conflicts. Each interface declares its own default methods, and there is no ambiguity about which implementation is used.
  • Scoped Usage: Since the default implementations serve purely as helpers, they are not extended with additional behavior that could lead to conflict.
Enhancing Testability and Modularity
  • Mockable Container Adapter: Because the default methods delegate to a static container adapter instance, you can easily provide a mock or a specialized test instance of the DI container. This allows tests to substitute the underlying service resolution logic without altering the interface itself.
  • Consistent Behavior: The default implementation establishes a uniform entry point for service resolution. This reduces boilerplate code and minimizes the risk of implementation discrepancies across different services.

Practical Example

Imagine an application where you have several service implementations that need to be resolved dynamically. The default implementations in IFactory<T> provide a concise, standardized way to access the DI container:

  1. Without Default Implementations:
    Each service consumer would have to manually acquire a reference to the DI container, leading to repeated boilerplate and potential inconsistencies.

  2. With Default Implementations (InterfaceFactory Approach):
    By calling IExample.GetInstance(), the consumer seamlessly accesses the registered service without having to worry about the DI container's internal details. The central adapter handles all nuances of service resolution, ensuring that the calling code remains clean and focused on domain logic.

In essence, the design of InterfaceFactory demonstrates that default implementations—when limited to delegation and devoid of business logic—can coexist with sound software architecture principles such as separation of concerns, modularity, and testability.


NuGet Packages

InterfaceFactory is available as two NuGet packages:

  • InterfaceFactory.Core
    Contains the core abstractions, attributes, and default factory implementations.

  • InterfaceFactory.DependencyInjection
    Provides integration and extensions for Microsoft.Extensions.DependencyInjection.

For more details, refer to the GitHub Repository.


Contributing

Contributions are welcome! Please see the Contributing Guidelines for details on how to propose improvements or report issues.


License

This project is licensed under the MIT License. See the LICENSE file for details.


We invite you to explore the repository and try out the NuGet packages. Should you have any questions or suggestions regarding the approach to Default Interface Implementations in InterfaceFactory, feel free to open an issue or reach out directly.

Product Compatible and additional computed target framework versions.
.NET net8.0 is compatible.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed.  net9.0 was computed.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  net10.0 was computed.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.
  • net8.0

    • No dependencies.

NuGet packages (2)

Showing the top 2 NuGet packages that depend on InterfaceFactory:

Package Downloads
WK.OpenAiWrapper

Package Description

InterfaceFactory.ContainerAdapter.DependencyInjection

Package Description

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
1.0.4 205 4/10/2025
1.0.3 137 3/29/2025
1.0.2 126 2/19/2025
1.0.1 105 2/19/2025
1.0.0 110 2/19/2025
0.1.4 114 2/19/2025
0.1.3 105 2/13/2025
0.1.2 108 2/7/2025
0.1.1 111 2/6/2025
0.1.0 111 2/6/2025