我正在编程的某些站点同时使用ASP.NET MVC和WebForms。
我有一个局部视图,我想将此包含在网络表单中。局部视图包含一些必须在服务器中处理的代码,因此使用Response.WriteFile不起作用。它应该与禁用的JavaScript一起工作。
我怎样才能做到这一点?
Answers:
我看了一下MVC的源代码,看是否能弄清楚该怎么做。控制器上下文,视图,视图数据,路由数据和html渲染方法之间似乎紧密耦合。
基本上,为了做到这一点,您需要创建所有这些额外的元素。它们中的一些相对简单(例如视图数据),但是却有些复杂-例如,路由数据将认为当前的WebForms页面将被忽略。
最大的问题似乎是HttpContext-MVC页面依赖于HttpContextBase(而不是像WebForms那样的HttpContext),尽管两者都实现了IServiceProvider,但它们并不相关。MVC的设计人员做出了一个明智的决定,即不更改旧版WebForm以使用新的上下文库,但是他们确实提供了包装器。
这可以工作,并且可以将部分视图添加到WebForm:
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 );
}
}
然后,您可以在WebForm中执行以下操作:
<% WebFormMVCUtil.RenderPartial( "ViewName", this.GetModel() ); %>
花了一段时间,但我找到了一个很好的解决方案。Keith的解决方案适用于很多人,但在某些情况下并不是最好的,因为有时您希望您的应用程序通过控制器的过程来渲染视图,而Keith的解决方案只是使用给定的模型来渲染视图。我在这里提出了一个可以正常运行的新解决方案。
一般步骤:
aspx
或中master page
,调用Utility方法来呈现部分传递Controller,视图的视图,并在需要时调用要呈现的模型(作为对象),在这个例子中让我们仔细检查一下
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
页面混合的剃刀视图时,这是一个很好的答案。(假设我们有一个名为Controller Home的Login的PartialView)。
<% MyApplication.MvcUtility.RenderAction("Home", "Login", new { }); %>
或者如果您有用于传递到动作的模型
<% MyApplication.MvcUtility.RenderAction("Home", "Login", new { Name="Daniel", Age = 30 }); %>
这个解决方案很棒,不使用ajax call,不会导致嵌套视图的渲染延迟,它不会创建新的WebRequest,因此不会为您带来新的会话,并且它将处理用于检索的方法所需视图的ActionResult,它无需传递任何模型即可工作
太好了,谢谢!
我在.NET 4上使用MVC 2,它要求将TextWriter传递到ViewContext中,因此您必须传递httpContextWrapper.Response.Output,如下所示。
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);
}
这是一种对我有用的类似方法。策略是将部分视图呈现为字符串,然后将其输出到WebForm页面中。
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 %>
希望有帮助!
该解决方案采用不同的方法。它定义了一个System.Web.UI.UserControl
可以放置在任何Web窗体上的,并可以配置为显示来自任何URL的内容,包括MVC部分视图。这种方法类似于HTML的AJAX调用,因为参数(如果有)通过URL查询字符串给出。
首先,在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,我需要能够从现有的Webforms代码动态呈现局部视图,并将其插入给定控件的顶部。我发现Keith的答案会导致部分视图呈现在<html />
标签外部。
我使用Keith和Hilarius的答案作为启发,而不是直接渲染到HttpContext.Current.Response.Output,而是渲染了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);
}