Требуется длительный процесс ASP.NET MVC с отзывами пользователей - PullRequest
44 голосов
/ 28 мая 2010

Я пытался создать контроллер в своем проекте для доставки, что может оказаться довольно сложным отчетом. В результате они могут занимать относительно много времени, и индикатор выполнения, безусловно, поможет пользователям узнать, что все идет вперед. Отчет будет запущен с помощью AJAX-запроса. Идея заключается в том, что периодические JSON-запросы будут получать статус и обновлять индикатор выполнения.

Я экспериментировал с AsyncController, так как это, кажется, хороший способ запуска длинных процессов без привязки ресурсов, но, похоже, он не дает мне никакого способа проверить прогресс (и, кажется, блокировать дальше JSON запрашивает, и я еще не выяснил, почему). После этого я попытался сохранить прогресс в статической переменной на контроллере и прочитать из него статус - но, честно говоря, все кажется немного странным!

Все предложения с благодарностью приняты!

Ответы [ 3 ]

48 голосов
/ 28 мая 2010

Вот пример, который я написал, чтобы вы могли попробовать:

Контроллер:

public class HomeController : AsyncController
{
    public ActionResult Index()
    {
        return View();
    }

    public void SomeTaskAsync(int id)
    {
        AsyncManager.OutstandingOperations.Increment();
        Task.Factory.StartNew(taskId =>
        {
            for (int i = 0; i < 100; i++)
            {
                Thread.Sleep(200);
                HttpContext.Application["task" + taskId] = i;
            }
            var result = "result";
            AsyncManager.OutstandingOperations.Decrement();
            AsyncManager.Parameters["result"] = result;
            return result;
        }, id);
    }

    public ActionResult SomeTaskCompleted(string result)
    {
        return Content(result, "text/plain");
    }

    public ActionResult SomeTaskProgress(int id)
    {
        return Json(new
        {
            Progress = HttpContext.Application["task" + id]
        }, JsonRequestBehavior.AllowGet);
    }
}

Индекс () Просмотр:

<script type="text/javascript">
$(function () {
    var taskId = 543;
    $.get('/home/sometask', { id: taskId }, function (result) {
        window.clearInterval(intervalId);
        $('#result').html(result);
    });

    var intervalId = window.setInterval(function () {
        $.getJSON('/home/sometaskprogress', { id: taskId }, function (json) {
            $('#progress').html(json.Progress + '%');
        });
    }, 5000);
});
</script>

<div id="progress"></div>
<div id="result"></div>

Идея состоит в том, чтобы запустить асинхронную операцию, которая будет сообщать о ходе выполнения, используя HttpContext.Application, означающее, что каждая задача должна иметь уникальный идентификатор. Затем на стороне клиента мы запускаем задачу и затем отправляем несколько запросов AJAX (каждые 5 с) для обновления хода выполнения. Вы можете настроить параметры в соответствии с вашим сценарием. Дальнейшим улучшением будет добавление обработки исключений.

6 голосов
/ 07 января 2015

4,5 года после ответа на этот вопрос, и у нас есть библиотека, которая может значительно облегчить эту задачу: SignalR. Нет необходимости использовать общее состояние (что плохо, поскольку может привести к непредвиденным результатам), просто используйте класс HubContext для подключения к концентратору, который отправляет сообщения клиенту.

Во-первых, мы устанавливаем соединение SignalR, как обычно (см., Например, здесь ), за исключением того, что нам не нужен какой-либо метод на стороне сервера в нашем концентраторе. Затем мы делаем AJAX-вызов к нашей конечной точке / контроллеру и т. Д. И передаем идентификатор соединения, который мы получаем, как обычно: var connectionId = $.connection.hub.id;. На стороне сервера вы можете запустить ваш процесс в другом потоке и вернуть 200 OK клиенту. Процесс будет знать идентификатор соединения, чтобы он мог отправлять сообщения обратно клиенту, например:

GlobalHost.ConnectionManager.GetHubContext<LogHub>()
                              .Clients.Client(connectionId)
                              .log(message);

Здесь log - это метод на стороне клиента, который вы хотите вызвать с сервера, поэтому он должен быть определен так же, как вы обычно делаете с SignalR:

$.connection.logHub.client.log = function(message){...};

Подробнее в моем блоге здесь

0 голосов
/ 15 января 2015

Если у вас есть доступ к вашему веб-серверу, вы можете создать службу Windows или простое консольное приложение для выполнения длительной работы. Ваше веб-приложение должно добавить запись в базу данных, чтобы указать, что операция должна начаться, а служба Windows, которая периодически проверяет наличие новых записей в базе данных, должна начать выполнять задачу и сообщать о ходе выполнения в базу данных. Ваше веб-приложение может использовать ajax-запрос для проверки прогресса и показа пользователям.

Я использовал этот метод для реализации отчетов Excel для приложения asp.net mvc. Этот отчет был создан службой Windows, которая работает на компьютере и постоянно проверяет наличие новых записей в таблице отчетов. Когда он находит новую запись, он начинает создавать отчет и отображает прогресс, обновляя поле записи. Приложение asp.net mvc только что добавляло новую запись отчета и отслеживало прогресс в базе данных до его завершения, а затем предоставило ссылку на готовый файл для загрузки.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...