2013-03-05 64 views
3

我有一个尝试解决方案在渲染ActionResult到字符串。我通过传递我自己的HttpContext来完成这项工作,它将输出文本编写器替换为我自己的TextWriter渲染ActionResult字符串 - 出现在不正确的顺序

下面是问题 - 元素呈现乱序。如果我通过直接通过浏览器查询来渲染局部视图,它可以正常工作。如果我通过替代文本编写器来渲染它,则无论在视图中的位置如何,剃须刀视图中的任何@ Html.Action元素都将首先呈现。

所以,这里是我的Razor视图:

@inherits System.Web.Mvc.WebViewPage<WebsitePresentationLayer.MgrScreenLayoutViewer> 
@using System.Web.Mvc.Html; 

<div> 
    @Model.DebugText 
</div> 
@foreach (var item in @Model.Items) 
{ 
    <div>@item.Title</div> 
    @Html.Action(
        "LayoutItem", 
        new 
        { 
         id = item.Id, 
         uniqueName = item.UniqueName 
        } 
       ); 

} 

如果我直接通过浏览器查询视图,它呈现在正确的顺序:

  • @ Model.DebugText
  • 项目1。标题
  • Item1动作渲染
  • Item2.Title
  • 项目2的描绘

如果我使这个对我的TextWriter,它呈现以下顺序:

  • 项目1的描绘
  • 项目2的描绘
  • @ Model.DebugText
  • Item1.Title
  • Item2.Title

为什么?

下面是我如何使用文本编写器进行编程。

StringBuilder sb = new StringBuilder(); 
StringWriter stringWriter = new StringWriter(sb); 

CMS.Website.MvcUtils.RenderControllerAction<PlayerGroupController> 
(
    c => c.ScreenLayout(this.MgrPlayerGroupViewer.ScreenLayoutId), 
    stringWriter 
); 
stringWriter.Flush(); 
var generatedString = sb.ToString(); 


:然后我终于将其输出到字符串使用下面的代码(我从ASP.NET Web窗体页面调用这个,所以已经有一个现有的 HttpContext

public static class ActionResultExtensions 
{ 
    internal class MyResponseWrapper : HttpResponseWrapper 
    { 
     private System.IO.TextWriter _textWriter; 
     public MyResponseWrapper(HttpResponse wrappedResponse, System.IO.TextWriter textWriter) 
      : base(wrappedResponse) 
     { 
      _textWriter = textWriter; 
     } 

     public override System.IO.TextWriter Output 
     { 
      get { return this._textWriter; } 
      set { this._textWriter = value; } 
     } 
    } 

    internal class MyHttpContextWrapper : HttpContextWrapper 
    { 
     private readonly System.IO.TextWriter _textWriter; 
     public MyHttpContextWrapper(System.IO.TextWriter textWriter) 
      : base(HttpContext.Current) 
     { 
      this._textWriter = textWriter; 
     } 

     public override HttpResponseBase Response 
     { 
      get 
      { 
       var httpResponse = HttpContext.Current.Response; 
       return new MyResponseWrapper(httpResponse, this._textWriter); 
      } 
     } 
    } 


    public static void Render(this System.Web.Mvc.ActionResult result, System.IO.TextWriter textWriter, System.Web.Routing.RouteData routeData, System.Web.Mvc.ControllerBase controllerBase) 
    { 
     var httpContextWrapper = new MyHttpContextWrapper(textWriter); 
     result.ExecuteResult(new System.Web.Mvc.ControllerContext(httpContextWrapper, routeData, controllerBase)); 
    } 
} 

public static class MvcUtils 
{ 
    public static void RenderControllerAction<T>(Func<T, System.Web.Mvc.ActionResult> f, System.IO.TextWriter writer) where T : System.Web.Mvc.ControllerBase, new() 
    { 
     var controller = new T(); 
     // We have to initialise the RouteData so that it knows the name of the controller 
     // This is used to locate the view 
     var typeName = controller.GetType().Name; 
     System.Text.RegularExpressions.Regex regex = new System.Text.RegularExpressions.Regex("(.*)Controller$"); 
     var match = regex.Match(typeName); 
     if (match.Success) 
     { 
      typeName = match.Groups[1].Value; 
     } 
     var routeData = new System.Web.Routing.RouteData(); 
     routeData.Values.Add("controller", typeName); 

     var actionResult = f(controller); 
     actionResult.Render(writer, routeData, controller); 
    } 
} 

而且 我写一个拦截器的TextWriter,果然,它接收三个电话到Write(string)

  • 写(LAYO utItem 1分的动作内容)
  • 写(LayoutItem 2项行动内容)
  • 写(Model.DebugText和两个项目冠军)

回答

3

我通过这个大约6个月前来到。目标是使用部分填充jquery弹出对话框。

问题是视图引擎想使它们在自己的尴尬为了...

试试这个。 LMK如果需要澄清。

public static string RenderPartialViewToString(Controller thisController, string viewName, object model) 
    { 
     // assign the model of the controller from which this method was called to the instance of the passed controller (a new instance, by the way) 
     thisController.ViewData.Model = model; 

     // initialize a string builder 
     using (StringWriter sw = new StringWriter()) 
     { 
      // find and load the view or partial view, pass it through the controller factory 
      ViewEngineResult viewResult = ViewEngines.Engines.FindPartialView(thisController.ControllerContext, viewName); 
      ViewContext viewContext = new ViewContext(thisController.ControllerContext, viewResult.View, thisController.ViewData, thisController.TempData, sw); 

      // render it 
      viewResult.View.Render(viewContext, sw); 

      //return the razorized view/partial-view as a string 
      return sw.ToString(); 
     } 
    } 
+0

谢谢。我不得不手动创建我自己的ControllerContext,但这解决了我的特殊问题。我仍然希望弄清楚为什么ViewEngine在我调用ActionResult.ExecuteResult时以一种奇怪的顺序渲染。 – 2013-03-06 00:52:55

+0

@AndrewShepherd我记得在这方面挣扎。起初,我只是试图返回一个部分,没有得到我想要的东西。我不得不通过控制器并通过它“处理”我的视图。一旦我决定了方向,一整天都会头朝天。你似乎在做类似的事情,但是来自一个稍微不同的方向。我必须再次深入了解它。 – 2013-03-06 01:34:31