You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

清洁架构下无需直接项目引用如何将基础设施服务注册到服务集合?

Solution: Register Infrastructure Services Without Project Reference in Clean Architecture

Great question! This is a key concern in clean architecture—maintaining strict layer boundaries while still enabling the cross-layer service registration you need. Luckily, there are two reliable approaches using reflection/assembly scanning that let you register your Infrastructure layer services without adding a direct project reference to Presentation.API, keeping your dependency graph clean.

Approach 1: Direct Reflection to Call AddInfrastructure

If you want to stick with your existing Add{ProjectName} method pattern, you can use reflection to load the Infrastructure assembly and invoke the static AddInfrastructure method directly.

Step-by-Step Implementation

  1. Ensure Infrastructure Assembly is Accessible: First, make sure the Infrastructure project's assembly gets copied to Presentation.API's output directory. You can do this by adding a project dependency (not a project reference):

    • Right-click Presentation.API in Solution Explorer → Project Dependencies → Check the box for your Infrastructure project. This ensures Infrastructure builds first and its assembly is copied to Presentation's output, without adding a compile-time reference.
  2. Reflectively Load and Invoke the Method: In your Presentation.API's startup code (e.g., Program.cs), use reflection to locate and call AddInfrastructure:

    using System.Reflection;
    
    // In your builder.Services configuration section
    var infrastructureAssemblyName = "YourSolution.Infrastructure"; // Match your actual assembly name
    var infrastructureAssembly = Assembly.Load(infrastructureAssemblyName);
    
    // Locate the class containing AddInfrastructure (e.g., InfrastructureExtensions)
    var extensionClass = infrastructureAssembly.GetType("YourSolution.Infrastructure.InfrastructureExtensions");
    if (extensionClass != null)
    {
        // Get the static AddInfrastructure method that accepts IServiceCollection
        var addMethod = extensionClass.GetMethod(
            "AddInfrastructure",
            BindingFlags.Public | BindingFlags.Static,
            new[] { typeof(IServiceCollection) }
        );
    
        // Invoke the method with your services collection
        addMethod?.Invoke(null, new object[] { builder.Services });
    }
    

Pros & Cons

  • Pros: Minimal changes to your existing code (reuses your AddInfrastructure method directly).
  • Cons: Hardcodes assembly and class names—you’ll need to update these if you rename the Infrastructure project or the class containing AddInfrastructure.

A more maintainable, scalable approach is to define a marker interface in your Domain layer (which Presentation already references) and have your Infrastructure layer implement it. This avoids hardcoding names and follows clean architecture principles.

Step-by-Step Implementation

  1. Define a Marker Interface in Domain: Add an interface to your Domain project that all dependency registration modules will implement:

    // In Domain project
    public interface IDependencyRegistrationModule
    {
        void RegisterServices(IServiceCollection services);
    }
    
  2. Implement the Interface in Infrastructure: Update your Infrastructure layer to wrap its registration logic in a class that implements this interface:

    // In Infrastructure project
    public class InfrastructureDependencyModule : IDependencyRegistrationModule
    {
        public void RegisterServices(IServiceCollection services)
        {
            // All your existing Infrastructure registration logic goes here
            services.AddDbContext<AppDbContext>(options => 
                options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));
            services.AddScoped<IUserRepository, UserRepository>();
            // ... any other Infrastructure services
        }
    }
    

    Note: You can reuse your existing AddInfrastructure method here by calling it inside RegisterServices if you prefer.

  3. Scan and Execute Modules in Presentation: In Presentation.API's startup code, scan all loaded assemblies for types implementing IDependencyRegistrationModule and invoke their registration methods:

    using System.Reflection;
    
    // In your builder.Services configuration section
    var moduleType = typeof(IDependencyRegistrationModule);
    var registrationModules = AppDomain.CurrentDomain.GetAssemblies()
        .SelectMany(assembly => assembly.GetTypes())
        .Where(type => moduleType.IsAssignableFrom(type) && !type.IsInterface && !type.IsAbstract)
        .Select(Activator.CreateInstance)
        .Cast<IDependencyRegistrationModule>();
    
    foreach (var module in registrationModules)
    {
        module.RegisterServices(builder.Services);
    }
    

Pros & Cons

  • Pros: No hardcoded names, follows open/closed principle (add new registration modules without changing Presentation code), and aligns with clean architecture's focus on domain-driven abstractions.
  • Cons: Requires adding a small interface to your Domain layer (a minor, acceptable tradeoff for maintainability).

Key Notes

  • Assembly Loading: Ensure the Infrastructure assembly is loaded into the AppDomain. The project dependency setup mentioned earlier will handle this by copying the assembly to Presentation's output directory.
  • Type Safety: While reflection sacrifices some compile-time type safety, both approaches keep Presentation completely isolated from Infrastructure's implementation details—you won’t be able to reference Infrastructure classes directly in Presentation, which is exactly what you want.

内容的提问来源于stack exchange,提问作者Ryan Gaudion

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.28 21:24:08