除Friend Assemblies外,还有哪些避免程序集泄漏的方法?
除了Friend Assemblies,以下几种方法可以有效防止程序集泄漏,限制特定程序集的访问权限:
1. 内部可见性+项目依赖管控
将基础设施项目中的实现类标记为internal,仅对外暴露必要的抽象接口(放在独立的应用层或契约项目中)。同时在解决方案层面严格管控项目引用:只允许Web项目直接引用基础设施项目,其他项目仅引用契约层的接口项目,无法直接访问基础设施的内部实现。
这种方式依赖编译时的项目依赖检查,一旦其他项目尝试引用基础设施项目,IDE会直接报错,适合结构清晰的分层架构(如Clean Architecture)。
2. 自定义Roslyn代码分析器
通过编写Roslyn分析器,在编译阶段检测非法引用行为:
- 分析器扫描所有项目的代码,检查是否有非允许的项目引用了基础设施项目的
public类型 - 一旦检测到违规引用,直接抛出编译警告或错误,从源头阻止程序集泄漏
示例核心逻辑:
public override void Initialize(AnalysisContext context) { context.RegisterSymbolAction(AnalyzeSymbol, SymbolKind.NamedType); } private void AnalyzeSymbol(SymbolAnalysisContext context) { var typeSymbol = (INamedTypeSymbol)context.Symbol; if (typeSymbol.ContainingAssembly.Name == "InfrastructureProject") { var referencingAssembly = context.Compilation.Assembly; if (referencingAssembly.Name != "WebProject") { context.ReportDiagnostic(Diagnostic.Create( Rule, typeSymbol.Locations[0], $"禁止{referencingAssembly.Name}引用基础设施项目的类型")); } } }
将这个分析器打包为NuGet包,添加到解决方案的所有项目中,即可实现编译时强制管控。
3. 依赖注入封装+接口隔离
在应用层定义抽象接口,基础设施项目以internal实现这些接口,同时提供一个仅允许Web项目调用的DI扩展方法:
// 应用层契约 public interface IOrderRepository { /* ... */ } // 基础设施层实现(internal) internal class EfCoreOrderRepository : IOrderRepository { /* ... */ } // 基础设施层的DI扩展(public) public static class InfrastructureServiceCollectionExtensions { public static IServiceCollection AddInfrastructure(this IServiceCollection services) { services.AddScoped<IOrderRepository, EfCoreOrderRepository>(); return services; } }
其他项目只能依赖应用层的IOrderRepository接口,无法直接访问EfCoreOrderRepository,而Web项目通过调用AddInfrastructure方法完成服务注册,间接使用基础设施实现。
4. 运行时调用方验证
在基础设施的public类型中添加运行时检查,验证调用方程序集是否为允许的Web项目:
public class PaymentService { public PaymentService() { var callingAssembly = Assembly.GetCallingAssembly(); var allowedAssemblyName = "WebProject"; var allowedPublicKeyToken = new byte[] { /* Web项目的公钥Token */ }; if (callingAssembly.GetName().Name != allowedAssemblyName || !callingAssembly.GetName().GetPublicKeyToken().SequenceEqual(allowedPublicKeyToken)) { throw new InvalidOperationException("仅允许Web项目调用此服务"); } } }
这种方式属于运行时防护,虽然无法阻止编译引用,但能在非法调用时直接抛出异常,适合需要动态验证的场景(如插件化架构)。
5. 强命名程序集+权限控制
给基础设施和Web项目添加强命名,然后通过.NET的权限系统限制访问:
- 为基础设施程序集设置自定义权限集,仅允许持有特定强命名密钥的Web程序集访问
- 在基础设施代码中通过
PermissionSet进行权限检查,拒绝未授权的调用方
这种方式配置较为复杂,适合对安全性要求极高的场景,通常结合代码访问安全(CAS)机制使用。
内容的提问来源于stack exchange,提问作者René

