jQuery 从 ASP.NET MVC 操作返回部分视图和 JSON
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/18667447/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Return Partial View and JSON from ASP.NET MVC Action
提问by nthpixel
I'm introducing KnockoutJS into an existing app. My plan is to modify/utilize the existing partial views that we've already created and bind them to the JS view models with Knockout's declarative attributes. When I make an AJAX call to an action, ideally I'd like the action to return both the HTML of the partial view and JSON object. Then I can fill a div with the HTML, convert the JSON to a Knockout object and bind it to the HTML. But I can't figure out how to return both from the action.
我正在将 KnockoutJS 引入现有的应用程序中。我的计划是修改/利用我们已经创建的现有部分视图,并将它们绑定到具有 Knockout 声明性属性的 JS 视图模型。当我对某个操作进行 AJAX 调用时,理想情况下我希望该操作同时返回部分视图的 HTML 和 JSON 对象。然后我可以用 HTML 填充一个 div,将 JSON 转换为 Knockout 对象并将其绑定到 HTML。但我不知道如何从动作中返回两者。
I need the full view model because I'll be updating it and eventually sending it back to the server.
我需要完整的视图模型,因为我将对其进行更新并最终将其发送回服务器。
I thought about having the action return the partial view (already bound to the model), and within the partial view, include javascript to convert the .Net model into a Knockout object. But I feel that scattering the JS around like that is messy and unmaintainable. I'd rather have everything close to the original ajax call.
我想过让动作返回局部视图(已经绑定到模型),并在局部视图中包含 javascript 以将 .Net 模型转换为 Knockout 对象。但我觉得像这样散布 JS 是混乱和不可维护的。我宁愿让一切都接近原始的 ajax 调用。
I guess another alternative is to make two action calls. One for the JSON, and another for the partial view. But there has to be a slicker way.
我想另一种选择是发出两个动作调用。一个用于 JSON,另一个用于局部视图。但必须有更巧妙的方法。
Any ideas on how best to do this?
关于如何最好地做到这一点的任何想法?
回答by Tim Medora
I'm sure there are a variety of ways to do this. I manually render the view from the controller, and then pass the rendered view back as part of my JSON response.
我确信有多种方法可以做到这一点。我从控制器手动渲染视图,然后将渲染的视图作为 JSON 响应的一部分传回。
This preserves the responsibilities of each entity. Views are still located using the view engine and they can be reused. The controller knows little or nothing about the view beyond its name and model type.
这保留了每个实体的责任。视图仍然使用视图引擎定位,它们可以被重用。除了名称和模型类型之外,控制器对视图知之甚少或一无所知。
Manual Rendering
手动渲染
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();
}
}
}
In your action method:
在您的操作方法中:
object model = null; // whatever you want
var obj = new {
someOtherProperty = "hello",
view = RenderHelper.PartialView( this, "_PartialName", model )
};
return Json( obj );
Note that I'm returning an anonymous type. You can return any (serializable) type you want, as long as it has a string property for the rendered view.
请注意,我返回的是匿名类型。你可以返回任何你想要的(可序列化的)类型,只要它具有渲染视图的字符串属性。
Testing
测试
Testing an action that uses manual rendering requires a slight modification. This is due to rendering the view a bit earlier than it would be rendered in the MVC pipeline.
测试使用手动渲染的动作需要稍作修改。这是因为渲染视图比在 MVC 管道中渲染的时间要早一些。
Manual Rendering
手动渲染
- Enter action method
- Render view explicitly <-- this will make it difficult to test the calling action
- Exit action method
- 输入动作方法
- 显式渲染视图 <-- 这将使测试调用操作变得困难
- 退出动作方法
Automatic Rendering
自动渲染
- Enter action method
- Create a view result
- Exit action method
- Process view result (thus rendering the view)
- 输入动作方法
- 创建查看结果
- 退出动作方法
- 处理视图结果(从而渲染视图)
In other words, our manual rendering process kicks off a variety of other operations that make it difficult to test (such as interacting with the build manager to compile the view).
换句话说,我们的手动渲染过程启动了许多其他难以测试的操作(例如与构建管理器交互以编译视图)。
Assuming you wish to test the action method and not the actual contents of the view, you can check whether or not the code is executing in a hosted environment.
假设您希望测试操作方法而不是视图的实际内容,您可以检查代码是否在托管环境中执行。
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
}
Checking HostingEnvironment.IsHosted
is inexpensive (under the hood, it is simply a null check).
检查HostingEnvironment.IsHosted
成本很低(在幕后,它只是一个空检查)。
回答by nwayve
You could create a hidden <input>
on the partial with a value set to the JSON string of the ViewModel. Then before you render the partial view, grab the JSON value from that field, and parse it. Then remove it from the partial view, insert it into your page, and do ko.applyBindingsToDescendants(viewModel, $("#parentElement")[0])
您可以<input>
使用设置为 ViewModel 的 JSON 字符串的值在部分上创建隐藏。然后在渲染局部视图之前,从该字段中获取 JSON 值并解析它。然后从局部视图中删除它,将其插入到您的页面中,然后执行ko.applyBindingsToDescendants(viewModel, $("#parentElement")[0])
I'm not entirely sure how I feel about this approach, and it's just a theory. I haven't tested this out but I suspect it would work. One booty trapyou'd have to look out for is the browser trying to cache your GET request. In your ajax request you'd want to do:
我不完全确定我对这种方法的感受,这只是一种理论。我还没有测试过,但我怀疑它会起作用。您必须注意的一个陷阱是浏览器试图缓存您的 GET 请求。在您的 ajax 请求中,您想要执行以下操作:
$.ajax({
url: "/",
type: 'GET',
cache: 'false'
});
Or just do a $.post
request.
(reference)
或者只是做一个$.post
请求。(参考)
So that's one option.
所以这是一种选择。