我正在将KnockoutJS引入现有的应用程序.我的计划是修改/利用我们已经创建的现有部分视图,并使用Knockout的声明属性将它们绑定到JS视图模型.当我对一个动作进行
AJAX调用时,理想情况下,我希望该动作返回部分视图和
JSON对象的HTML.然后我可以用HTML填充div,将JSON转换为Knockout对象并将其绑定到HTML.但是我不知道如何从动作中返回.
我需要完整的视图模型,因为我会更新它,并最终将其发送回服务器.
我想到有一个操作返回部分视图(已经绑定到模型),并且在部分视图中,包含javascript以将.Net模型转换为Knockout对象.但是我觉得像这样散布JS就是凌乱而不可知的.我宁愿把一切都贴近原来的ajax电话.
我想另外一个选择是进行两个动作调用.一个用于JSON,另一个用于部分视图.但是必须有一个较小的方式.
任何想法如何最好地做到这一点?
解决方法
我相信有很多方法可以做到这一点.我从控制器手动渲染视图,然后将渲染的视图作为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,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是廉价的(在引擎盖下,它只是一个空的检查).