Обратный вызов AsyncController не вызывается, как его вызвать?

Здравствуйте, я пытаюсь реализовать AsynController,

вот мой код:

[NoCache]
public class GraphController : BaseAsyncController
{
    private readonly IReportsRepository _reportsRepository;
    private readonly ISqlQueryRepository _sqlQueryRepository;

    //Background worker
    private readonly BackgroundWorker _worker = new BackgroundWorker();

    public GraphController(ISqlQueryRepository sqlQueryRepository, IReportsRepository reportsRepository)
    {
        _sqlQueryRepository = sqlQueryRepository;
        _reportsRepository = reportsRepository;
    }

    public void Index()
    {
        AsyncManager.OutstandingOperations.Increment();

        _worker.DoWork += (sender, args) =>
        {
            AsyncManager.Parameters["message"] = "hello world";
            Thread.Sleep(3000);
        };

        _worker.RunWorkerCompleted += (sender, args) => AsyncManager.OutstandingOperations.Decrement();
        //run the worker
        _worker.RunWorkerAsync();
    }

    public ActionResult IndexCompleted(string message) //callback not being invoked
    {
        ViewData["message"] = message;
        return View();
    }
}

Вопрос в том, почему завершенный обратный вызов не вызывается?

Заранее спасибо.


person IamStalker    schedule 14.03.2012    source источник


Ответы (1)


Название вашего действия неверно. Не должно быть Index. Должно быть IndexAsync. Взгляните на следующую статью, в которой показано использование асинхронных контроллеров в ASP.NET MVC.

Обратите внимание, что BackgroundWorker — это компонент Windows Form. Не используйте компоненты WinForms в приложениях ASP.NET. Они не предназначены для использования в серверных приложениях. Я бы порекомендовал вам TPL.

So:

[NoCache]
public class GraphController : BaseAsyncController
{
    private readonly IReportsRepository _reportsRepository;
    private readonly ISqlQueryRepository _sqlQueryRepository;

    public GraphController(ISqlQueryRepository sqlQueryRepository, IReportsRepository reportsRepository)
    {
        _sqlQueryRepository = sqlQueryRepository;
        _reportsRepository = reportsRepository;
    }

    public void IndexAsync()
    {
        AsyncManager.OutstandingOperations.Increment();
        Task.Factory.StartNew(() => 
        {
            // do the work
            Thread.Sleep(3000);

            // the work is finished => pass the results and decrement
            AsyncManager.Parameters["message"] = "hello world";
            AsyncManager.OutstandingOperations.Decrement();
        });
    }

    public ActionResult IndexCompleted(string message)
    {
        ViewData["message"] = message;
        return View();
    }
}
person Darin Dimitrov    schedule 14.03.2012
comment
@IamStalker, я бы порекомендовал TPL. Создавать потоки вручную никогда не бывает хорошей идеей. Создать нить может быть довольно дорого. Используя TPL, вы получите больше преимуществ от таких вещей, как автоматическое объединение потоков, планирование задач и распределение по различным доступным ядрам ЦП, ... вещи, для достижения которых вам нужно написать сотни строк кода, если вы работаете с потоками вручную. Не говоря уже о грядущем выпуске .NET 4.5, который полностью основан на концепции задач. - person Darin Dimitrov; 14.03.2012
comment
спасибо, во-первых, за объяснение, во-вторых, у меня, я бы сказал, простой вопрос, почему IndexAsync имеет значение, какое имя действия? - person IamStalker; 14.03.2012
comment
@IamStalker, да, имя имеет значение. Вам нужно 2 метода: первый — XXXAsync, а второй — XXXCompleted, где XXX — это имя вашего действия, которое вы бы использовали в URL-адресе для запроса: /graph/xxx. Пожалуйста, прочитайте статью, на которую я ссылаюсь в своем ответе. Все это довольно хорошо объясняется. - person Darin Dimitrov; 14.03.2012