Pergunta

eu tenho um SearchController com uma ação que pode executar algumas pesquisas de longa duração e retornar uma página de resultados. As pesquisas podem levar de 1 a 60 segundos. O URL para uma pesquisa é uma solicitação HTTP do formulário: http://localhost/Search?my=query&is=fancy

A experiência que estou procurando é semelhante aos muitos sites de viagem que estão por aí. Eu gostaria de mostrar uma página intermediária de "carregamento ..." onde, idealmente:

  1. O usuário pode recarregar a página sem reiniciar a pesquisa
  2. Depois que a pesquisa de back-end é concluída, o usuário é redirecionado para os resultados
  3. A experiência degrada para navegadores com JavaScript desativado
  4. O histórico de botão traseiro / navegador não deve incluir esta página intersticial.
  5. No caso de uma pesquisa curta (1 segundo), ela não tem um impacto significativo no tempo para chegar aos resultados ou à experiência (página significativamente feia flashes, o que for)

Esses são bons de ter. Estou aberto a todas as idéias! Obrigado.

Foi útil?

Solução

Você poderia fazer isso da seguinte maneira:

  • Faça a solicitação de pesquisa (o URL GET) com Ajax
  • O URL de pesquisa não retorna os resultados, mas retorna algum conteúdo JSON ou XML com o URL dos resultados reais
  • A página do cliente mostra uma mensagem "Carregando ..." enquanto aguarda a chamada do AJAX para terminar
  • A página do cliente redireciona para a página de resultados quando concluída.

Um exemplo usando 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>

(editar:)

O controlador seria algo como:

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

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

Considere pseudo-código: eu realmente não o testei.

Outras dicas

Para mantê-lo sem javascript, você pode dividir a pesquisa em várias ações.

A primeira ação (/search/? Q = whodunit) apenas faz uma validação de seus parâmetros (para que você saiba se precisa exibir novamente o formulário) e depois retorna uma visualização que usa uma meta-refrescamento para apontar o navegador de volta para A ação de pesquisa "real".

Você pode implementar isso com duas ações controladoras separadas (digamos, pesquisa e resultados):

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(...);
    }
}

Mas isso lhe dá alguns obstáculos no que diz respeito a refrescantes. Assim, você pode transmitir novamente em uma única ação que pode sinalizar o processo em duas fases usando o 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(...);
    }
}

Isso abrange os pontos 2, 3, 4 e sem dúvida 5.

Incluir o suporte para o número 1 implica que você armazenará os resultados da pesquisa em sessão, DB, etc.

Nesse caso, basta adicionar a implementação de cache desejada como parte do bit "fazer pesquisa real aqui" e adicionar um recente de check-for para contornar a página de carregamento. por exemplo

if (TempData[SearchLoadingPageSentKey]==null)

torna-se

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

Boa pergunta. Em breve, posso ter que implementar uma solução semelhante no ASP.NET MVC, mas acho que não exigiria uma implementação fundamentalmente diferente da solução baseada em Webforms, da qual existem vários exemplos na rede:

Eu já criei uma implementação com base no primeiro link acima com os formulários da Web. O processo básico é:

  1. A página inicial é solicitada com parâmetros de pesquisa
  2. Esta página inicia um novo tópico que executa a tarefa de longa data
  3. Esta página redireciona o usuário para uma página de "em processo", que possui um cabeçalho de atualização HTTP definido para recarregar a cada dois segundos
  4. O thread executando as atualizações de pesquisa um objeto "global" estático de progresso de pesquisa indicando o % completo e a página de processo em processo lê, exibindo o progresso. (Cada pesquisa é armazenada por um ID do GUID em uma hashtable, portanto várias pesquisas simultâneas são suportadas)
  5. Depois de concluir o thread, atualiza o progresso da pesquisa como tal e quando a página de processo em processo detecta isso, ele redireciona para uma página final de "resultado".

(Definitivamente, verifique o segundo link do MSDN, é uma solução bem diferente, mas não uma que eu apenas desviei.)

O benefício disso é que ele não requer JavaScript. A maior desvantagem em que consigo pensar (da perspectiva de um usuário) é que ele não é totalmente "web 2.0" e os usuários terão que esperar uma série de atualizações do navegador.

Algo baseado na sugestão baseada no Ajax de @jan willem b deve ser uma alternativa viável a esse padrão de estado de espera com vários threades. O que melhor atende às suas necessidades é algo que você terá que decidir por conta própria. O exemplo do ASPFree.com que publiquei deve atender à maioria dos seus requisitos e trabalhar tão bem com o MVC quanto os formulários da Web.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top