3

を文字列にレンダリングする際の解決策を試みましActionResultた。HttpContextこれは、出力テキスト ライターを my own に置き換えるmy own を渡すことで行いますTextWriter

ここに問題があります - 要素が順不同でレンダリングされています。ブラウザーから直接クエリを実行して部分ビューをレンダリングすると、正常に動作します。代替テキスト ライターを使用してレンダリングすると、ビュー内の位置に関係なく、カミソリ ビュー内の @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
  • Item1.タイトル
  • Item1 アクション レンダリング
  • Item2.タイトル
  • Item2 アクションレンダリング

これを TextWriter にレンダリングすると、次の順序でレンダリングされます。

  • Item1 アクション レンダリング
  • Item2 アクションレンダリング
  • @Model.DebugText
  • Item1.タイトル
  • Item2.タイトル

なんで?

テキストライターを代用する方法は次のとおりです。(私はこれを ASP.NET WebForms ページから呼び出しているため、既存の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);
    }
}

そして、最終的に次のコードを使用して文字列に出力します。

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();


のインターセプターを作成しましたが、TextWriter案の定、それは への 3 つの呼び出しを受信して​​います。Write(string)

  • Write(LayoutItem 1アクション内容)
  • 書き込み(LayoutItem 2アクション内容)
  • 書き込み (Model.DebugText と 2 つの項目のタイトル)
4

1 に答える 1

3

私は約6ヶ月前にこれを経験しました。目標は、パーシャルを使用して jquery ポップアップ ダイアログに入力することでした。

問題は、View Engine がそれらを独自の厄介な順序でレンダリングしたいということです...

これを試して。明確化が必要な場合は 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();
        }
    }
于 2013-03-06T00:11:40.540 に答える