を文字列にレンダリングする際の解決策を試みまし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 つの項目のタイトル)