代码之家  ›  专栏  ›  技术社区  ›  eKek0

如何在Web表单中包含局部视图

  •  82
  • eKek0  · 技术社区  · 17 年前

    我正在编程的某个网站同时使用ASP。NET MVC和WebForms。

    我有一个局部视图,我想把它包含在一个webform中。局部视图有一些代码必须在服务器中处理,因此使用Response。WriteFile不起作用。 它应该在禁用javascript的情况下工作。

    我该怎么做?

    7 回复  |  直到 16 年前
        1
  •  101
  •   Keith    16 年前

    我查看了MVC源代码,看看我是否能弄清楚如何做到这一点。控制器上下文、视图、视图数据、路由数据和html呈现方法之间似乎存在非常紧密的耦合。

    最大的问题似乎是HttpContext-MVC页面依赖于HttpContextBase(而不是像WebForms那样依赖于HttpContext),虽然两者都实现了IServiceProvider,但它们并不相关。MVC的设计者们深思熟虑地决定不改变遗留的WebForms来使用新的上下文库,但他们确实提供了一个包装器。

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

    <% WebFormMVCUtil.RenderPartial( "ViewName", this.GetModel() ); %>
    
        2
  •  41
  •   Dale K    6 年前

    完成控制器的流程 用于渲染视图,以及 Keith的解决方案只是用给定的模型渲染视图

    一般步骤:

    1. 创建实用程序类
    2. 在你的 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 });
        }
    

        public class RenderActionViewModel
        {
            public string ControllerName { get; set; }
            public string ActionName { get; set; }
            public object RouteValues { get; set; }
        }
    

    DummyController

        //Here the Dummy controller with Dummy view
        public class DummyController : Controller
        {
          public ActionResult PartialRender()
          {
              return PartialView();
          }
        }
    

    PartialRender.cshtml (剃刀视图) 虚拟控制器 对于以下内容,请注意,它将使用Html辅助程序执行另一个渲染操作。

    @model Portal.MVC.MvcUtility.RenderActionViewModel
    @{Html.RenderAction(Model.ActionName, Model.ControllerName, Model.RouteValues);}
    

    MasterPage 页面 母板页 页面 页。(假设我们有一个名为控制器主页登录的PartialView)。

        <% MyApplication.MvcUtility.RenderAction("Home", "Login", new { }); %>
    

    或者,如果你有一个进入行动的模型

        <% MyApplication.MvcUtility.RenderAction("Home", "Login", new { Name="Daniel", Age = 30 }); %>
    

    这个解决方案很棒, 不使用ajax调用 ,这不会导致 对于嵌套视图,它 所以 不会为您带来新的会话 ,而且 将处理检索ActionResult的方法

    多亏了 Using MVC RenderAction within a Webform

        3
  •  20
  •   Andrew Whitaker    13 年前

    类似这样(使用jQuery)

    <div id="mvcpartial"></div>
    
    <script type="text/javascript">
    $(document).load(function () {
        $.ajax(
        {    
            type: "GET",
            url : "urltoyourmvcaction",
            success : function (msg) { $("#mvcpartial").html(msg); }
        });
    });
    </script>
    
        4
  •  11
  •   Dr. Hilarius    14 年前

    我正在使用MVC 2。NET 4需要将TextWriter传递到ViewContext中,因此您必须传入httpContextWrapper。回应。输出如下图所示。

        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);
        }
    
        5
  •  6
  •   aarondcoleman    14 年前

    这是一种类似的方法,对我来说一直有效。其策略是将部分视图呈现为字符串,然后在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 %>
    

    希望这能有所帮助!

        6
  •  3
  •   Bill Heitstuman    11 年前

    这个解决方案采取了不同的方法。它定义了一个 System.Web.UI.UserControl 这种方法类似于HTML的AJAX调用,因为参数(如果有的话)是通过URL查询字符串给出的。

    /控件/PartialViewControl.ascx文件

    <%@ Control Language="C#" 
    AutoEventWireup="true" 
    CodeFile="PartialViewControl.ascx.cs" 
    Inherits="PartialViewControl" %>
    

    /控件/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);
            }
        }
    }
    

    <%@ 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/"  />
    
        7
  •  1
  •   lukep    7 年前

    FWW,我需要能够从现有的webforms代码中动态渲染部分视图,并将其插入到给定控件的顶部。我发现Keith的回答会导致部分视图在外部呈现 <html />

    使用Keith和Hilarius的答案作为灵感,而不是直接呈现给HttpContext。电流。回应。输出时,我呈现了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);
        }