2012-01-04 3 views
2

У меня есть действие фильтр NHibernate, который устанавливает и распоряжается сессия/сделки следующим образом:Почему метод OnActionExecuted моего ActionFilterAttribute запускается до завершения операции async?

public class NHibernateActionAttribute : ActionFilterAttribute 
{ 
    public ISessionFactory SessionFactory { get; set; } 

    public override void OnActionExecuting(ActionExecutingContext filterContext) 
    { 
     // inject nhibernate session into controller 
     // and start transaction 
    } 

    public override void OnActionExecuted(ActionExecutedContext filterContext) 
    { 
     // commit or rollback and dispose 
    } 
} 

события огнь штраф по методу синхронного действия, но когда у меня есть действие асинхронных такие, как показано ниже , метод OnActionExecuted фильтра действий срабатывает, как только возвращается первый метод async.

public void SomeOperationAsync(term) 
{ 
    object results = null 
    var worker = new BackgroundWorker(); 

    worker.DoWork += (o,e) => 
    { 
     // Do some lengthy DB query 
     AsyncManager.Parameters["result"] = results; 
     AsyncManager.OutstandingOperations.Decrement(); 
    }; 

    AsyncManager.OutstandingOperations.Increment(); 
    worker.RunWorkerAsync();   
    // OnActionExecuted fires NOW. 
} 

public ActionResult SomeOperationCompleted(object result) 
{ 
    return Json(result, JsonRequestBehavior.AllowGet); 
    // I would expect OnActionExecuted to fire NOW. 
} 

Проблема заключается в том, что, поскольку OnActionExecuted метод стрельбы в то время как моя асинхронная работа все еще делаются, запрос дб в фоновом режиме работника не удается, потому что сессия уже закрыта. Как я могу это исправить?

+0

hmmm ... неужели вы действительно создаете фонаря? Я еще не использовал AsyncController, но я просто предположил, что он будет обрабатывать асинхронный аспект для вас ... – dotjoe

+0

Существует несколько способов сделать это. Если вы используете какой-либо сервис или компонент, который предоставляет собственные методы типа BeginWork и EndWork, вы просто подключаетесь к ним. Поскольку я просто выполняю асинхронный случайный кодовый блок, я использую класс BackgroundWorker для предоставления асинхронных объектов. – Chris

+0

ах, поэтому, когда вы вызываете Increment(), он должен блокироваться до тех пор, пока код рабочего фона не вызовет Decrement()? Кроме того, я не думаю, что ISession - это потокобезопасный ... так что же тут использовать async? – dotjoe

ответ

0

Я понятия не имею, как BackgroundWorker ведет себя в среде ASP.NET, но вы можете работать с классом Task. Попробуйте следующее:

public void SomeOperationAsync(term) { 

    AsyncManager.OutstandingOperations.Increment(); 

    Task<object>.Factory.StartNew(() => { 

     object results = null 

     // Do some lengthy DB query 

     return results; 

    }).ContinueWith(t => { 

     AsyncManager.Parameters["result"] = t.Result; 
     AsyncManager.OutstandingOperations.Decrement(); 
    }); 
} 
+0

Я только что пробовал с вашим кодом и без костей. Запрос по-прежнему не удается из-за ObjectDisposedException («session closed!»). – Chris

+0

@ Chris интересно. Вы делали что-либо еще внутри метода SomeOperationAsync? – tugberk

+0

Нет. Я полагаю, что корень моей проблемы заключается в том, что OnActionExecuted не является «асинхронным». Он возвращается после завершения первого метода, а не когда AsyncManager выполняет обратный вызов Completed. Я понятия не имею, почему, хотя, или как исправить ... – Chris

Смежные вопросы