Удалите прослушиватель событий из асинхронного контроллера по таймауту - PullRequest
0 голосов
/ 13 марта 2012

У меня проблема с асинхронным контроллером MVC3. Когда асинхронный метод контроллера запускается, я увеличиваю асинхронный контроллер и также начинаю слушать события бэкэнда

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

А затем, когда запускается внутреннее событие, я уменьшаю и отписываюськ внутренним событиям

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

Это работает, но если время ожидания контроллера истекло, eventAggregator будет хранить подписку на контроллер (это список Weakrefence, но по какой-то причине старый контроллер не удаляется) и когда событие внутреннего события запускаетсястарый контроллер сначала украдет событие и выведет из него события, то есть, когда реальный контроллер получит сообщение, очередь пуста и ничто не отправлено в представление, также это утечка памяти, поэтому в списке Weakreference у нас будет много контроллеров послепару минут ... Как я могу отписать контроллер от Eventaggregator, когда он истекает?

edit: Код для агрегатора событий, у нас есть модульные тесты для этого кода, которые доказывают отсутствие утечек памяти.Странно то, что если я создаю пустой стандартный контроллер без каких-либо ссылок на что-либо, его деконструктор тоже не запускается ... Мы используем 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 Ответ

1 голос
/ 13 марта 2012

Вы можете переопределить метод EndExecute :

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

И для определения периода ожидания вы можете использовать атрибут [AsyncTimeout].

...