在超时时从异步控制器中删除事件侦听器

时间:2012-03-13 08:59:25

标签: asp.net-mvc-3 asynccontroller

我遇到了MVC3异步控制器的问题,当控制器asyc方法运行时,我增加了asyncontroller并开始监听rebnd事件

AsyncManager.OutstandingOperations.Increment();
eventAggregator.Subscribe(this);

然后当后端事件触发时,我会减少并取消订阅后端事件

AsyncManager.OutstandingOperations.Decrement(); 
eventAggregator.Unsubscribe(this);

这样可行,但是如果控制器超时,eventAggregator将保留对控制器的订阅(它是一个Weakrefence列表,但是因为某些原因,旧控制器没有被删除),并且当后端事件触发旧控制器时将首先窃取事件并且将事件出列意味着当真实控制器获取消息时队列为空并且没有任何内容发送到视图时,这也是内存泄漏所以我们将在Weakreference列表中有很多控制器需要几分钟...怎么能我在超时时取消订阅eventaggregator的控制器吗?

编辑:事件聚合器的代码,我们对此代码进行了单元测试,证明没有内存泄漏。奇怪的是,如果我创建一个没有任何引用的空标准控制器,它的解构函数也不会运行......我们使用IoC(Ninject)会出现问题吗?

public class EventAggregator : IEventAggregator
{
    private readonly IConfig config;
    private readonly WeakReferenceList<object> subscribers = new WeakReferenceList<object>(); 

    public EventAggregator(IConfig config)
    {
        this.config = config;
    }

    public void Subscribe(object subsriber)
    {
        subscribers.Add(subsriber);
    }

    public void Unsubscribe(object subscriber)
    {
        subscribers.Remove(subscriber);
    }

    public void Publish<T>(T message) where T : class
    {
        var lookupType = typeof (IHandle<T>);

        if (config.EnableEventAggregator)
            subscribers.Where(lookupType.IsInstanceOfType)
            .Select(s => s as IHandle<T>)
            .ForEach(s => s.Handle(message));
    }
}

public class WeakReferenceList<T> : ICollection<T> where T : class
{
    private readonly List<WeakReference> list = new List<WeakReference>(); 

    public IEnumerator<T> GetEnumerator()
    {
        return GetAlive().Select(item => item.Target as T).GetEnumerator();
    }

    IEnumerator IEnumerable.GetEnumerator()
    {
        return GetEnumerator();
    }

    public void Add(T item)
    {
        CleanDeadReferences();
        list.Add(new WeakReference(item));
    }

    public void Clear()
    {
        list.Clear();
    }

    public bool Contains(T item)
    {
        return GetAlive().Any(weakItem => weakItem.Target.Equals(item));
    }

    public void CopyTo(T[] array, int arrayIndex)
    {
        throw new NotImplementedException();
    }

    public bool Remove(T item)
    {
        CleanDeadReferences();
        return list.RemoveAll(weakItem => weakItem.Target.Equals(item)) > 0;
    }

    public int Count
    {
        get { return GetAlive().Count(); }
    }

    public bool IsReadOnly
    {
        get { return false; }
    }

    public int IndexOf(T item)
    {
        var weakItem = list.First(x => x.Target == item);
        return list.IndexOf(weakItem);
    }

    public void Insert(int index, T item)
    {
        CleanDeadReferences();
        list.Insert(index, new WeakReference(item));
    }

    private IEnumerable<WeakReference> GetAlive()
    {
        return list.ToList().Where(item => item.IsAlive);
    }

    private void CleanDeadReferences()
    {
        list.RemoveAll(item => !item.IsAlive);
    }
}

1 个答案:

答案 0 :(得分:1)

您可以覆盖EndExecute方法:

protected override void EndExecute(IAsyncResult asyncResult)
{
    try
    {
        base.EndExecute(asyncResult);
    }
    catch(TimeoutException ex)
    {
        // Clean up your references here
    }
}

要定义超时期限,您可以使用[AsyncTimeout]属性。