Как реализовать промежуточную страницу «загрузка ...» в ASP.NET MVC? - PullRequest
6 голосов
/ 30 октября 2009

У меня есть SearchController с действием, которое может выполнять некоторые длительные поиски и возвращать страницу результатов. Поиск может занять от 1 до 60 секунд. URL для поиска - HTTP-запрос GET в форме: http://localhost/Search?my=query&is=fancy

Опыт, который я ищу, похож на множество туристических сайтов. Я хотел бы показать промежуточную страницу "Загрузка ...", где, в идеале:

  1. Пользователь может перезагрузить страницу, не возобновляя поиск
  2. После того, как внутренний поиск завершен, пользователь перенаправляется к результатам
  3. Опыт ухудшается для браузеров с отключенным JavaScript
  4. Кнопка «Назад» / история браузера не должна включать эту промежуточную страницу.
  5. В случае короткого поиска (1 секунда) это не оказывает существенного влияния ни на время, чтобы добраться до результатов, ни на опыт (значительно уродливые страницы, что угодно)

Это хорошо, чтобы иметь. Я открыт для всех идей! Спасибо.

Ответы [ 3 ]

5 голосов
/ 30 октября 2009

Чтобы сохранить его без JavaScript, вы можете разбить поиск на несколько действий.

Первое действие (/ Search /? Q = whodunit) просто выполняет некоторую проверку ваших параметров (чтобы вы знали, нужно ли повторно отображать форму), а затем возвращает представление, которое использует мета-обновление, чтобы указать браузер возвращается к «реальному» поисковому действию.

Вы можете реализовать это с помощью двух отдельных действий контроллера (скажем, «Поиск» и «Результаты»):

public ActionResult Search(string q)
{
    if (Validate(q))
    {
        string resultsUrl = Url.Action("Results", new { q = q });
        return View("ResultsLoading", new ResultsLoadingModel(resultsUrl));
    }
    else
    {
        return ShowSearchForm(...);
    }
}

bool Validate(string q)
{
    // Validate
}

public ActionResult Results(string q)
{
    if (Validate(q))
    {
        // Do Search and return View
    }
    else
    {
        return ShowSearchForm(...);
    }
}

Но это дает вам некоторые препятствия в плане освежения. Таким образом, вы можете объединить их обратно в одно действие, которое может сигнализировать о двухфазном процессе с использованием TempData.

static string SearchLoadingPageSentKey = "Look at me, I'm a magic string!";

public ActionResult Search(string q)
{
    if (Validate(q))
    {
        if (TempData[SearchLoadingPageSentKey]==null)
        {
            TempData[SearchLoadingPageSentKey] = true;
            string resultsUrl = Url.Action("Search", new { q = q });
            return View("ResultsLoading", new ResultsLoadingModel(resultsUrl));
        }
        else
        {
            // Do actual search here
            return View("SearchResults", model);
        }
    }
    else
    {
        return ShowSearchForm(...);
    }
}

Это охватывает пункты 2, 3, 4 и, возможно, 5.

Включение поддержки # 1 подразумевает, что вы собираетесь хранить результаты поиска в сеансе, в БД и т. Д.

В этом случае просто добавьте желаемую реализацию кеша как часть бита «Делать фактический поиск здесь» и добавьте check-for-cached-result, чтобы обойти страницу загрузки. например,

if (TempData[SearchLoadingPageSentKey]==null)

становится

if (TempData[SearchLeadingPageSentKey]==null && !SearchCache.ContainsKey(q))

2 голосов
/ 30 октября 2009

Хороший вопрос. Вскоре мне, возможно, придется внедрить подобное решение в asp.net mvc, но я не думаю, что это потребует принципиально иной реализации, чем решение на основе веб-форм, из которых в сети есть различные примеры:

Ранее я создавал реализацию на основе первой ссылки выше с веб-формами. Основной процесс:

  1. Запрашивается начальная страница с параметрами поиска
  2. На этой странице запускается новый поток, выполняющий долгосрочную задачу
  3. Эта страница перенаправляет пользователя на страницу «в процессе», в которой установлен заголовок обновления http для перезагрузки каждые пару секунд
  4. Поток, выполняющий поиск, обновляет «глобальный» статический объект прогресса поиска, указывающий% выполнения, и страница, находящаяся в процессе обработки, считывает с него информацию о ходе выполнения. (каждый поиск сохраняется по идентификатору GUID в Hashtable, поэтому поддерживается несколько одновременных поисков)
  5. После завершения поток обновляет ход поиска как таковой, и когда страница, находящаяся в процессе обработки, обнаруживает это, он перенаправляется на конечную страницу «результатов».

(Обязательно проверьте вторую ссылку из MSDN, это совсем другое решение, но не то, которое я только просмотрел).

Преимущество этого в том, что ему вообще не нужен Javascript. Самый большой недостаток, который я могу себе представить (с точки зрения пользователя), заключается в том, что это не совсем «Web 2.0», и пользователям придется ждать через серию обновлений браузера.

Нечто, основанное на предложении @Jan Willem B на основе AJAX, должно стать жизнеспособной альтернативой этому многопоточному шаблону состояний ожидания. Что лучше всего соответствует вашим требованиям - это то, что вам придется решать самостоятельно. Приведенный мною пример с aspfree.com должен соответствовать большинству ваших требований и работать с MVC так же хорошо, как веб-формы.

2 голосов
/ 30 октября 2009

Вы можете сделать это следующим образом:

  • выполнить поисковый запрос (URL GET) с помощью AJAX
  • URL-адрес поиска не возвращает результаты, но возвращает некоторое содержимое Json или XML с URL-адресом фактических результатов
  • на странице клиента отображается сообщение "загрузка ..." в ожидании завершения вызова AJAX
  • клиентская страница перенаправляется на страницу результатов после завершения.

Пример использования jquery:

<div id="loading" style="display: none">
  Loading...
</div>
<a href="javascript:void(0);" 
  onclick="searchFor('something')">Search for something</a>

<script type="text/javascript">
  function searchFor(what) {
    $('#loading').fadeIn();
    $.ajax({ 
      type: 'GET', 
      url: 'search?query=' + what, 
      success: function(data) { 
        location.href = data.ResultsUrl; 
      } 
    });        
  }
</script>

(редактирование:)

Контроллер будет выглядеть примерно так:

public class SearchController 
{
  public ActionResult Query(string q) 
  {
    Session("searchresults") = performSearch();
    return Json(new { ResultsUrl = 'Results'});
  }

  public ActionResult Results()
  {
    return View(Session("searchresults"));
  }
}

Считайте, что это псевдокод: на самом деле я его не тестировал.

...