Webフォーム内に部分ビューを含める方法
-
22-08-2019 - |
質問
私がプログラミングしている一部のサイトでは、ASP.NET MVC と WebForms の両方を使用しています。
部分的なビューがあり、これを Web フォーム内に含めたいと考えています。部分ビューにはサーバーで処理する必要があるコードが含まれているため、Response.WriteFile の使用は機能しません。JavaScriptを無効にしても動作するはずです。
これどうやってするの?
解決
私はこれを行う方法を見つけ出すことができるかどうかを確認するにはMVCのソースを見ていました。方法をレンダリングコントローラコンテキスト、ビュー、ビューデータ、ルーティングデータとHTMLの間の非常に密結合があるように思われる。
基本的にはこれを実現するために、あなたはこれらの余分なすべての要素を作成する必要があります。それらのいくつかは(このようなビューデータなど)は比較的簡単ですが、いくつかは、もう少し複雑です - インスタンスのルーティングデータは、現在のWebフォームページが無視されるように検討します。
。の大きな問題はのHttpContextのように見える - MVCのページは、に依存しているHttpContextBaseを(むしろ、WebフォームのようなのHttpContextより行う)とIServiceProviderを実装し、両方の間、彼らが関係していません。 MVCの設計者は、しかし、彼らはラッパーを提供した、新しいコンテキストベースを使用する従来のWebフォームを変更しない意図的な決断を下した。
これは、あなたがWebフォームへの部分的なビューを追加することができます動作します:
public class WebFormController : Controller { }
public static class WebFormMVCUtil
{
public static void RenderPartial( string partialName, object model )
{
//get a wrapper for the legacy WebForm context
var httpCtx = new HttpContextWrapper( System.Web.HttpContext.Current );
//create a mock route that points to the empty controller
var rt = new RouteData();
rt.Values.Add( "controller", "WebFormController" );
//create a controller context for the route and http context
var ctx = new ControllerContext(
new RequestContext( httpCtx, rt ), new WebFormController() );
//find the partial view using the viewengine
var view = ViewEngines.Engines.FindPartialView( ctx, partialName ).View;
//create a view context and assign the model
var vctx = new ViewContext( ctx, view,
new ViewDataDictionary { Model = model },
new TempDataDictionary() );
//render the partial view
view.Render( vctx, System.Web.HttpContext.Current.Response.Output );
}
}
次に、あなたのWebフォームにあなたがこれを行うことができます:
<% WebFormMVCUtil.RenderPartial( "ViewName", this.GetModel() ); %>
他のヒント
時間はかかりましたが、素晴らしい解決策を見つけました。Keith のソリューションは多くの人にとって機能しますが、特定の状況では最適ではありません。 コントローラーのプロセスを通過する ビューをレンダリングするため、そして Keith のソリューションは、指定されたモデルでビューをレンダリングするだけです ここでは、通常のプロセスを実行する新しいソリューションを紹介します。
一般的な手順:
- ユーティリティクラスを作成する
- ダミービューを使用してダミーコントローラーを作成する
- あなたの中で
aspx
またはmaster page
, 、ユーティリティ メソッドを呼び出して、コントローラーを渡して部分的にレンダリングし、必要に応じて (オブジェクトとして) レンダリングするモデルを表示します。
この例で詳しく確認してみましょう
1) というクラスを作成します。 MVCUtility
そして、次のメソッドを作成します。
//Render a partial view, like Keith's solution
private static void RenderPartial(string partialViewName, object model)
{
HttpContextBase httpContextBase = new HttpContextWrapper(HttpContext.Current);
RouteData routeData = new RouteData();
routeData.Values.Add("controller", "Dummy");
ControllerContext controllerContext = new ControllerContext(new RequestContext(httpContextBase, routeData), new DummyController());
IView view = FindPartialView(controllerContext, partialViewName);
ViewContext viewContext = new ViewContext(controllerContext, view, new ViewDataDictionary { Model = model }, new TempDataDictionary(), httpContextBase.Response.Output);
view.Render(viewContext, httpContextBase.Response.Output);
}
//Find the view, if not throw an exception
private static IView FindPartialView(ControllerContext controllerContext, string partialViewName)
{
ViewEngineResult result = ViewEngines.Engines.FindPartialView(controllerContext, partialViewName);
if (result.View != null)
{
return result.View;
}
StringBuilder locationsText = new StringBuilder();
foreach (string location in result.SearchedLocations)
{
locationsText.AppendLine();
locationsText.Append(location);
}
throw new InvalidOperationException(String.Format("Partial view {0} not found. Locations Searched: {1}", partialViewName, locationsText));
}
//Here the method that will be called from MasterPage or Aspx
public static void RenderAction(string controllerName, string actionName, object routeValues)
{
RenderPartial("PartialRender", new RenderActionViewModel() { ControllerName = controllerName, ActionName = actionName, RouteValues = routeValues });
}
パラメーターを渡すためのクラスを作成します。ここで RendeActionViewModel を呼び出します (MvcUtility クラスの同じファイル内に作成できます)。
public class RenderActionViewModel
{
public string ControllerName { get; set; }
public string ActionName { get; set; }
public object RouteValues { get; set; }
}
2) 次に、という名前のコントローラーを作成します。 DummyController
//Here the Dummy controller with Dummy view
public class DummyController : Controller
{
public ActionResult PartialRender()
{
return PartialView();
}
}
というダミービューを作成します。 PartialRender.cshtml
(カミソリビュー) DummyController
次のコンテンツでは、HTML ヘルパーを使用して別のレンダリング アクションが実行されることに注意してください。
@model Portal.MVC.MvcUtility.RenderActionViewModel
@{Html.RenderAction(Model.ActionName, Model.ControllerName, Model.RouteValues);}
3) さあ、これをあなたのものに入れてください。 MasterPage
または aspx
ファイルを使用して、必要なビューを部分的にレンダリングします。これは、複数のかみそりのビューを組み合わせたい場合に最適な答えであることに注意してください。 MasterPage
または aspx
ページ。(コントローラー ホームに Login という PartialView があると仮定します)。
<% MyApplication.MvcUtility.RenderAction("Home", "Login", new { }); %>
または、アクションに渡すためのモデルがある場合
<% MyApplication.MvcUtility.RenderAction("Home", "Login", new { Name="Daniel", Age = 30 }); %>
このソリューションは素晴らしいです、 ajax呼び出しを使用しません, を引き起こすことはありません。 遅延レンダリング ネストされたビューの場合、 新しい WebRequest を作成しません それはそう 新しいセッションは提供されません, 、そしてそれ ActionResultを取得するメソッドを処理します。 あなたが望む景色のために、 モデルを渡さずに動作します
最も明白な方法AJAX経由だろう。
このような何か(jQueryのを使用して)
<div id="mvcpartial"></div>
<script type="text/javascript">
$(document).load(function () {
$.ajax(
{
type: "GET",
url : "urltoyourmvcaction",
success : function (msg) { $("#mvcpartial").html(msg); }
});
});
</script>
これは素晴らしいです、ありがとう!
あなたは以下に示すように内httpContextWrapper.Response.Output合格する必要がありますので、私は、ViewContextに渡さたTextWriterを必要と.NET 4、上MVC 2を使用しています。
public static void RenderPartial(String partialName, Object model)
{
// get a wrapper for the legacy WebForm context
var httpContextWrapper = new HttpContextWrapper(HttpContext.Current);
// create a mock route that points to the empty controller
var routeData = new RouteData();
routeData.Values.Add(_controller, _webFormController);
// create a controller context for the route and http context
var controllerContext = new ControllerContext(new RequestContext(httpContextWrapper, routeData), new WebFormController());
// find the partial view using the viewengine
var view = ViewEngines.Engines.FindPartialView(controllerContext, partialName).View as WebFormView;
// create a view context and assign the model
var viewContext = new ViewContext(controllerContext, view, new ViewDataDictionary { Model = model }, new TempDataDictionary(), httpContextWrapper.Response.Output);
// render the partial view
view.Render(viewContext, httpContextWrapper.Response.Output);
}
ここでは私のために働いてきた同様のアプローチです。戦略は、Webフォームページにおける出力つまり、その後、文字列に部分的なビューをレンダリングすることです。
public class TemplateHelper
{
/// <summary>
/// Render a Partial View (MVC User Control, .ascx) to a string using the given ViewData.
/// http://www.joeyb.org/blog/2010/01/23/aspnet-mvc-2-render-template-to-string
/// </summary>
/// <param name="controlName"></param>
/// <param name="viewData"></param>
/// <returns></returns>
public static string RenderPartialToString(string controlName, object viewData)
{
ViewDataDictionary vd = new ViewDataDictionary(viewData);
ViewPage vp = new ViewPage { ViewData = vd};
Control control = vp.LoadControl(controlName);
vp.Controls.Add(control);
StringBuilder sb = new StringBuilder();
using (StringWriter sw = new StringWriter(sb))
{
using (HtmlTextWriter tw = new HtmlTextWriter(sw))
{
vp.RenderControl(tw);
}
}
return sb.ToString();
}
}
ページの分離コードでは、あなたが行うことができます。
public partial class TestPartial : System.Web.UI.Page
{
public string NavigationBarContent
{
get;
set;
}
protected void Page_Load(object sender, EventArgs e)
{
NavigationVM oVM = new NavigationVM();
NavigationBarContent = TemplateHelper.RenderPartialToString("~/Views/Shared/NavigationBar.ascx", oVM);
}
}
とページにあなたがレンダリングされたコンテンツにアクセスすることができます。
<%= NavigationBarContent %>
助け希望!
このソリューションは、異なるアプローチをとります。これは、任意のWebフォーム上の場所にすることができ、任意のURL ... MVC部分ビューを含むからのコンテンツを表示するように構成されSystem.Web.UI.UserControl
を定義します。
URLのクエリ文字列を経由して与えられている(もしあれば)は、このアプローチは、そのパラメータにHTMLのためのAJAX呼び出しに似ています。
まず、2つのファイルにユーザーコントロールを定義します:
/controls/PartialViewControl.ascxファイル
<%@ Control Language="C#"
AutoEventWireup="true"
CodeFile="PartialViewControl.ascx.cs"
Inherits="PartialViewControl" %>
/controls/PartialViewControl.ascx.csます:
public partial class PartialViewControl : System.Web.UI.UserControl {
[Browsable(true),
Category("Configutation"),
Description("Specifies an absolute or relative path to the content to display.")]
public string contentUrl { get; set; }
protected override void Render(HtmlTextWriter writer) {
string requestPath = (contentUrl.StartsWith("http") ? contentUrl : "http://" + Request.Url.DnsSafeHost + Page.ResolveUrl(contentUrl));
WebRequest request = WebRequest.Create(requestPath);
WebResponse response = request.GetResponse();
Stream responseStream = response.GetResponseStream();
var responseStreamReader = new StreamReader(responseStream);
var buffer = new char[32768];
int read;
while ((read = responseStreamReader.Read(buffer, 0, buffer.Length)) > 0) {
writer.Write(buffer, 0, read);
}
}
}
そして、あなたのWebフォームページにユーザーコントロールを追加します:
<%@ Page Language="C#" %>
<%@ Register Src="~/controls/PartialViewControl.ascx" TagPrefix="mcs" TagName="PartialViewControl" %>
<h1>My MVC Partial View</h1>
<p>Below is the content from by MVC partial view (or any other URL).</p>
<mcs:PartialViewControl runat="server" contentUrl="/MyMVCView/" />
FWIW、私は、既存のWebフォームのコードから動的部分ビューをレンダリングし、指定したコントロールの最上部にそれを挿入できるようにする必要がありました。私はキースの答えは<html />
タグの外にレンダリングされる部分図を引き起こす可能性があることを見つけます。
HttpContext.Current.Response.Outputに直接描画するのではなく、インスピレーションのためのキースとHilariusから回答を使用して、私は、HTML文字列をレンダリングし、関連するコントロールにLiteralControlとしてこれを追加します。
静的ヘルパークラスでます:
public static string RenderPartial(string partialName, object model)
{
//get a wrapper for the legacy WebForm context
var httpCtx = new HttpContextWrapper(HttpContext.Current);
//create a mock route that points to the empty controller
var rt = new RouteData();
rt.Values.Add("controller", "WebFormController");
//create a controller context for the route and http context
var ctx = new ControllerContext(new RequestContext(httpCtx, rt), new WebFormController());
//find the partial view using the viewengine
var view = ViewEngines.Engines.FindPartialView(ctx, partialName).View;
//create a view context and assign the model
var vctx = new ViewContext(ctx, view, new ViewDataDictionary { Model = model }, new TempDataDictionary(), new StringWriter());
// This will render the partial view direct to the output, but be careful as it may end up outside of the <html /> tag
//view.Render(vctx, HttpContext.Current.Response.Output);
// Better to render like this and create a literal control to add to the parent
var html = new StringWriter();
view.Render(vctx, html);
return html.GetStringBuilder().ToString();
}
クラスを呼び出すには:
internal void AddPartialViewToControl(HtmlGenericControl ctrl, int? insertAt = null, object model)
{
var lit = new LiteralControl { Text = MvcHelper.RenderPartial("~/Views/Shared/_MySharedView.cshtml", model};
if (insertAt == null)
{
ctrl.Controls.Add(lit);
return;
}
ctrl.Controls.AddAt(insertAt.Value, lit);
}