使用jQuery ajax渲染ASP.NET MVC部分视图

6

我有一个控制器动作,它渲染了一个局部视图:

public ActionResult Details(int id)
{
    DetailsViewModel model = 
        ModelBuilder.GetDetailsViewModel(id, _repository);
    return PartialView("Details", model);
}

我将返回的内容加载到一个动态元素中,方法如下:
$container = appendContainer(); // adds a div to the dom with the correct id
$container.load("MyController/Details", function(response, status, xhr) {
    if (status != "success") {
        $(container).html('an error has occured');
    }
});

所以这将创建一个div,然后将返回的内容加载到该div中。
我希望稍微修改一下,以便只有在调用控制器成功时才创建容器div。
所以:
  1. jQuery调用控制器操作
  2. 控制器返回PartialView,如果未找到Id则返回null
  3. 如果返回了PartialView,则创建容器并使用返回的内容进行加载。
  4. 如果控制器未找到Id,则不创建任何内容并显示警报。
我会感激您对如何最好实现这一点的任何指导。
2个回答

12

在你的情况下,我会使用$.ajax而不是.load(),这样可以更好地控制流程并且感觉更加清晰。

$.ajax({
url: "MyController/Details",
   type: "GET",
   success: function (response, status, xhr)
   {
      var jqContainer = appendContainer();
      jqContainer.html(response);
   },
   error:function(XMLHttpRequest, textStatus, errorThrown)
   {
     //show the error somewhere - but this is a bad solution
   }
});
关于错误状态-我也不喜欢依赖异常-它既丑陋又低效,你有几种处理方式:
  1. 只从视图返回JSON并使用某种模板解决方案绑定返回的数据,这样你可以返回一个具有特定错误消息的错误对象,并以相同的方式处理所有错误(认为这是最好的解决方法)。
  2. 返回204成功状态码-没有响应,就像从您的操作返回null一样-然后检查状态代码并弹出错误消息。
  3. 返回278个成功状态码(不是真实的状态代码,但计入成功并可让您发送数据)-在这里,您发送一个带有错误消息的JSON对象,您可以解析并显示一个漂亮的错误消息(曾经在SO中看到过这个278解决方案)。
  4. 为错误返回不同的视图-但那么您必须将其插入容器或虚拟容器以检查是否存在错误,如果您想采取更多行动。

在我的代码中,我使用$(document).ajaxSend(..)全局检查所有Ajax响应以获得278代码,并在有错误消息时显示错误消息,或调用原始的挂钩成功函数。

要从操作返回错误,我使用以下结果

    public class AjaxErrorWithDetailsResult : JsonResult
    {
    public object ErrorResult { get; set; }

    public AjaxErrorWithDetailsResult(object errorResult)
    {
        this.ErrorResult = errorResult;
    }


    public override void ExecuteResult(ControllerContext context)
    {
        if (context == null)
        {
            throw new ArgumentNullException("context");
        }
        this.Data = ErrorResult;
        context.HttpContext.Response.StatusCode = 278;
        base.ExecuteResult(context);
    }
}

其中ErrorResult可以是匿名对象,也可以是实现了一个具有ErrorMessage属性的接口的对象,因此您将知道在JS中要查找什么。


1
我同意你的观点!$ajax能够更好地控制流程。 - Luis.Andrade

11

所有load做的就是从服务器返回HTML,那么为什么不只是将其附加到临时

中,然后在成功后从中获取HTML呢?

var $dummy = $("<div>");
$dummy.load("MyController/Details", function(response, status, xhr) {
    var $container = appendContainer();
    if (status != "success") {
        $container.html('an error has occured');
    }
    else
    {
        $container.html($dummy.html());
    }
    $dummy.remove();
});

更新:

如果你预计会出现异常,那么你应该处理它。如果你仅仅为了得到status != "success"而允许错误发生,那么这是一种严重的代码问题。你应该捕获异常并返回一个不同的PartialView。

public ActionResult Details(int id)
{
    try
    {
        DetailsViewModel model = 
            ModelBuilder.GetDetailsViewModel(id, _repository);
        return PartialView("Details", model);
    }
    catch (SomeException ex)
    {
        return PartialView("Error", ex.Message);
    }
}

如果这样做,您就可以保证始终获得有效的HTML响应。如果没有,那么基本错误an error occured将出现。


我的保留意见是,我基本上是在我的视图中使用未捕获的异常来返回一个空/未找到状态给用户界面。如果找不到该项,我宁愿从控制器返回null,但我无法看到如何使这种方法与之配合工作。对我来说,这似乎有点代码异味。 - fearofawhackplanet

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接