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

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

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

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

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

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

【问题讨论】:

    标签: jquery asp.net-mvc json knockout.js


    【解决方案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 管道中渲染要早一些。

    手动渲染

    1. 输入操作方法
    2. 显式渲染视图
    3. 退出操作方法

    自动渲染

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

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

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

        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 在客户端上到底需要什么,但视图也需要一个模型(即使它为空)。
    猜你喜欢
    • 2017-01-30
    • 2010-09-18
    • 1970-01-01
    • 2011-06-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多