6

我有一个SearchController,其动作可以执行一些长时间运行的搜索并返回结果页面。搜索可能需要 1 到 60 秒。搜索的 URL 是一个 HTTP GET 请求,格式如下:http://localhost/Search?my=query&is=fancy

我正在寻找的体验类似于那里的许多旅游网站。我想显示一个中间“正在加载...”页面,理想情况下:

  1. 用户无需重新开始搜索即可重新加载页面
  2. 后端搜索完成后,用户将被重定向到结果
  3. 禁用 JavaScript 的浏览器体验会降低
  4. 后退按钮/浏览器历史记录不应包含此插页式页面。
  5. 在短搜索(1 秒)的情况下,它不会对获得结果的时间或体验产生重大影响(非常难看的页面闪烁,无论如何)

这些都是不错的。我对所有想法持开放态度!谢谢。

4

3 回答 3

5

为了保持 javascript-less,您可以将搜索分解为多个操作。

第一个操作 (/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 的支持意味着您将在会话、数据库等中存储搜索结果。

在这种情况下,只需将所需的缓存实现添加为“在此处进行实际搜索”位的一部分,并添加一个检查缓存结果以绕过加载页面。例如

if (TempData[SearchLoadingPageSentKey]==null)

变成

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

于 2009-10-30T18:17:58.223 回答
2

您可以通过以下方式进行操作:

  • 使用 AJAX 执行搜索请求(GET url)
  • 搜索 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"));
  }
}

将其视为伪代码:我实际上并未对其进行测试。

于 2009-10-30T17:47:33.997 回答
2

好问题。我可能很快就必须自己在 asp.net mvc 中实现一个类似的解决方案,但我认为它不需要与基于 webforms 的解决方案完全不同的实现,其中网络上有各种示例:

我之前已经基于上面的第一个链接使用 Web 表单构建了一个实现。基本流程是:

  1. 使用搜索参数请求初始页面
  2. 此页面启动一个执行长时间运行任务的新线程
  3. 此页面将用户重定向到“处理中”页面,该页面有一个 http 刷新标头设置为每隔几秒重新加载一次
  4. 执行搜索的线程更新一个“全局”静态搜索进度对象,指示完成百分比,并且正在处理的页面从中读取,显示进度。(每次搜索都由一个 GUID id 存储在 Hashtable 中,因此支持多个并发搜索)
  5. 一旦完成,线程就会更新搜索进度,当正在处理的页面检测到这一点时,它会重定向到最终的“结果”页面。

(一定要检查 MSDN 的第二个链接,这是完全不同的解决方案,但不是我只是略过的一个。)

这样做的好处是它根本不需要 Javascript。我能想到的最大缺点(从用户的角度来看)是它并不完全是“Web 2.0”,用户将不得不等待一系列浏览器刷新。

基于@Jan Willem B 的基于 AJAX 的建议的东西应该是这种多线程等待状态模式的可行替代方案。哪个最能满足您的要求是您必须自行决定的。我发布的来自 aspfree.com 的示例应该可以满足您的大部分要求,并且可以与 MVC 和 Web 表单一起使用。

于 2009-10-30T18:55:33.593 回答