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

应用闲置数小时后使用ServiceLocator获取IXXXXXController触发激活错误求助

问题分析与解决方案

这问题我在维护Prism MEF项目时碰到过,核心和MEF的弱引用缓存机制以及闲置时的GC回收行为有关,咱们一步步拆解:

原因剖析

从错误堆栈里的WeakReferenceCollection.CleanupDeadReferences就能看出端倪:MEF默认对共享(Shared)部件是用弱引用存储的。当应用长时间闲置时,系统会触发垃圾回收(GC),如果你的IXXXXXController实例没有被其他强引用持有,就会被GC回收。后续再通过ServiceLocator获取时,MEF找不到已缓存的实例,尝试重新激活又因为依赖链上的部件可能也被回收,最终抛出激活错误。

你的配置里用AssemblyCatalog添加了程序集,但MEF的默认共享策略就是弱引用追踪,这才导致闲置后出问题。

解决方案

根据你的需求(是否需要单例),可以选下面的方案:

方案1:改为非共享实例(适合不需要单例的场景)

给IXXXXXController的实现类添加PartCreationPolicy特性,指定每次获取都创建新实例,彻底避开弱引用缓存的问题:

[Export(typeof(IXXXXXController))]
[PartCreationPolicy(CreationPolicy.NonShared)]
public class XXXXXController : IXXXXXController
{
    // 类实现代码
}

这样每次调用ServiceLocator.Current.GetInstance<IXXXXXController>()都会生成新实例,不会依赖MEF的弱引用缓存,自然不会被GC回收导致激活失败。

方案2:保持单例,添加强引用持有(适合需要单例的场景)

如果你的控制器必须是单例,那就在应用启动时提前获取实例,并用一个静态变量保持强引用,阻止GC回收:

public class YourBootstrapper : MefBootstrapper
{
    // 静态变量持有强引用,防止GC回收实例
    private static IXXXXXController _cachedController;

    protected override void InitializeShell()
    {
        // 提前获取实例并缓存
        _cachedController = ServiceLocator.Current.GetInstance<IXXXXXController>();
        base.InitializeShell();
    }

    protected override void ConfigureAggregateCatalog()
    {
        base.ConfigureAggregateCatalog();
        this.AggregateCatalog.Catalogs.Add(new AssemblyCatalog(typeof(ClassName).Assembly));
    }
}

这个静态变量会一直持有实例的强引用,GC不会回收它,后续再获取时MEF就能找到缓存的实例。

方案3:尽量避免直接使用ServiceLocator(推荐最佳实践)

ServiceLocator其实是反模式,建议改用构造函数注入的方式获取依赖。比如在需要使用IXXXXXController的类里,直接把它作为构造参数:

[Export]
public class SomeService
{
    private readonly IXXXXXController _controller;

    // 通过构造函数注入,MEF会自动管理生命周期
    [ImportingConstructor]
    public SomeService(IXXXXXController controller)
    {
        _controller = controller;
    }
}

这种方式MEF会更可靠地追踪实例的引用关系,减少因为间接获取导致的生命周期问题。

额外检查点

  • 确认IXXXXXController的实现类确实标注了[Export(typeof(IXXXXXController))]特性,没有写错导出类型。
  • 确认ConfigureAggregateCatalog里添加的程序集确实包含该控制器的实现类(typeof(ClassName).Assembly里的ClassName要和控制器在同一个程序集)。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.15 08:29:38