Нужен многостраничный процесс ASP.NET MVC с обратной связью с пользователем
Я пытаюсь создать контроллер в своем проекте для доставки того, что может оказаться довольно сложным. В результате они могут занять относительно много времени, и индикатор прогресса, безусловно, поможет пользователям узнать, что все идет вперед. Отчет будет запущен через запрос AJAX, и идея состоит в том, что периодические запросы JSON получат статус и обновят индикатор выполнения.
Я экспериментировал с AsyncController, так как кажется, что это хороший способ запуска длинных процессов без привязки ресурсов, но он, похоже, не дает мне возможности проверить прогресс (и, похоже, блокирует дальнейшие JSON, и я пока не обнаружил, почему). После этого я пробовал прибегать к сохранению прогресса в статической переменной на контроллере и чтении статуса из этого - но, честно говоря, все кажется немного взломанным!
Все предложения с благодарностью приняты!
Ответы
Ответ 1
В этом примере я написал, что вы можете попробовать:
Контроллер:
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 секунд) для обновления прогресса. Вы можете настроить параметры, чтобы приспособиться к вашему сценарию. Дальнейшее улучшение будет заключаться в добавлении обработки исключений.
Ответ 2
Через 4,5 года после ответа на этот вопрос у нас есть библиотека, которая может облегчить эту задачу: SignalR. Нет необходимости использовать разделяемое состояние (что плохо, потому что это может привести к неожиданным результатам), просто используйте класс HubContext для подключения к концентратору, который отправляет сообщения клиенту.
Сначала мы установили соединение SignalR, как обычно (см., например, здесь), за исключением того, что нам не нужен какой-либо серверный метод на нашем Хабе. Затем мы вызываем вызов AJAX нашей конечной точке/контроллеру/независимо и передаем идентификатор соединения, который мы получаем как обычно: var connectionId = $.connection.hub.id;
. На стороне сервера вы можете начать свой процесс в другом потоке и перенаправить 200 OK клиенту. Процесс будет знать connectionId, чтобы он мог отправлять сообщения обратно клиенту, например:
GlobalHost.ConnectionManager.GetHubContext<LogHub>()
.Clients.Client(connectionId)
.log(message);
Здесь log
- это метод на стороне клиента, который вы хотите вызвать с сервера, поэтому его следует определить так, как вы обычно делаете с SignalR:
$.connection.logHub.client.log = function(message){...};
Подробнее в своем блоге здесь
Ответ 3
Если у вас есть доступ к вашей машине веб-сервера в качестве выбора, вы можете создать службу Windows или простое консольное приложение для выполнения долговременной работы. Ваше веб-приложение должно добавить запись в db, чтобы указать, что операция должна начинаться, и ваша служба Windows, которая периодически проверяет наличие новых записей в db, должна начать выполнять задачу и сообщить о прогрессе в db.
Ваше веб-приложение может использовать запрос ajax для проверки прогресса и показа пользователям.
Я использовал этот метод для реализации отчетов excel для приложения asp.net mvc.
Этот отчет был создан службой Windows, которая работает на машине и постоянно проверяет наличие новых записей в таблице отчетов, и когда она находит новую запись, она начинает создавать отчет и указывать прогресс, обновляя поле записи. Приложение Asp.net mvc просто добавляет новую отчетную запись и отслеживает прогресс в базе данных до ее завершения, а затем предоставляет ссылку на готовый файл для загрузки.