从 ASP.NET MVC 操作返回部分视图和 JSON

Posted

技术标签:

【中文标题】从 ASP.NET MVC 操作返回部分视图和 JSON【英文标题】:Return Partial View and JSON from ASP.NET MVC Action 【发布时间】:2013-09-11 02:59:48 【问题描述】:

我正在将 KnockoutJS 引入现有应用程序。我的计划是修改/利用我们已经创建的现有局部视图,并将它们绑定到具有 Knockout 声明性属性的 JS 视图模型。当我对一个动作进行 AJAX 调用时,理想情况下,我希望该动作返回部分视图的 html 和 JSON 对象。然后我可以用 HTML 填充 div,将 JSON 转换为 Knockout 对象并将其绑定到 HTML。但我不知道如何从操作中返回两者。

我需要完整视图模型,因为我将对其进行更新并最终将其发送回服务器。

我想过让动作返回部分视图(已经绑定到模型),并在部分视图中包含 javascript 以将 .Net 模型转换为 Knockout 对象。但是我觉得像这样分散 JS 是混乱和不可维护的。我宁愿让一切都接近原始的 ajax 调用。

我想另一种选择是进行两个动作调用。一个用于 JSON,另一个用于局部视图。但必须有更巧妙的方式。

关于如何最好地做到这一点的任何想法?

【问题讨论】:

【参考方案1】:

您可以在部分上创建一个隐藏的<input>,并将值设置为 ViewModel 的 JSON 字符串。然后在渲染局部视图之前,从该字段中获取 JSON 值,并对其进行解析。然后从局部视图中删除它,将其插入到您的页面中,然后执行ko.applyBindingsToDescendants(viewModel, $("#parentElement")[0])

我不完全确定我对这种方法的感受,这只是一种理论。我没有对此进行测试,但我怀疑它会起作用。您必须注意的一个booty trap 是浏览器试图缓存您的GET 请求。在您想要做的 ajax 请求中:

$.ajax(
  url: "/",
  type: 'GET',
  cache: 'false'
);

或者只是做一个$.post 请求。 (reference)

所以这是一种选择。

【讨论】:

+1 表示该选项...但我也不确定我对此有何感受。【参考方案2】:

我确信有多种方法可以做到这一点。我从控制器手动渲染视图,然后将渲染的视图作为 JSON 响应的一部分传回。

这保留了每个实体的责任。视图仍然使用视图引擎定位,并且可以重复使用。除了名称和模型类型之外,控制器对视图知之甚少或一无所知。

手动渲染

public static class RenderHelper

    public static string PartialView( Controller controller, string viewName, object model )
    
        controller.ViewData.Model = model;

        using( var sw = new StringWriter() )
        
            var viewResult = ViewEngines.Engines.FindPartialView( controller.ControllerContext, viewName );
            var viewContext = new ViewContext( controller.ControllerContext, viewResult.View, controller.ViewData, controller.TempData, sw );

            viewResult.View.Render( viewContext, sw );
            viewResult.ViewEngine.ReleaseView( controller.ControllerContext, viewResult.View );

            return sw.ToString();
        
    

在您的操作方法中:

object model = null; // whatever you want
var obj = new  
    someOtherProperty = "hello", 
    view = RenderHelper.PartialView( this, "_PartialName", model ) 
;

return Json( obj );

请注意,我返回的是匿名类型。你可以返回任何你想要的(可序列化的)类型,只要它有一个用于渲染视图的字符串属性。

测试

测试使用手动渲染的动作需要稍作修改。这是因为渲染视图比在 MVC 管道中渲染要早一些。

手动渲染

    输入操作方法 显式渲染视图 退出操作方法

自动渲染

    输入操作方法 创建查看结果 退出操作方法 处理视图结果(从而渲染视图)

换句话说,我们的手动渲染过程会启动各种其他难以测试的操作(例如与构建管理器交互以编译视图)。

假设您希望测试操作方法而不是视图的实际内容,您可以检查代码是否在托管环境中执行。

    public static string PartialView( Controller controller, string viewName, object model )
    
        // returns false from a VS 2013 unit test, true from IIS
        if( !HostingEnvironment.IsHosted )
        
            // return whatever you want here
            return string.Empty;
        

        // continue as usual
     

检查HostingEnvironment.IsHosted 的成本很低(实际上,它只是一个空检查)。

【讨论】:

+1 从来没有考虑过辅助类。这可能是最优雅的解决方案。我会试一试。谢谢。 您不想这样做吗:var obj = new view = RenderHelper.PartialView(this, "_PartialName", viewModel), model = koViewModel ;?或者这就是'foo'?还是我错过了什么? @Dennis - 是的,“foo”代表您需要返回的任何其他数据。我不确定 Knockout 在客户端上到底需要什么,但视图也需要一个模型(即使它为空)。

以上是关于从 ASP.NET MVC 操作返回部分视图和 JSON的主要内容,如果未能解决你的问题,请参考以下文章

在 ASP.NET MVC 站点中返回视图时操作页面滚动

从asp.net mvc的部分视图中的文本框中获取值

如何在 ASP.NET MVC 视图中返回当前操作?

ASP.NET MVC 将部分视图呈现为字符串以返回 JSON [重复]

ASP.NET MVC 中返回视图的 URL

使用 ASP.NET MVC 4 从控制器调用另一个不同的视图