Pregunta Cómo incluir una vista parcial dentro de un formulario web


Algunos sitios que estoy programando usan ASP.NET MVC y WebForms.

Tengo una vista parcial y quiero incluir esto dentro de un formulario web. La vista parcial tiene algún código que debe procesarse en el servidor, por lo que el uso de Response.WriteFile no funciona. Debería funcionar con javascript deshabilitado.

¿Cómo puedo hacer esto?


73
2018-03-31 19:50


origen


Respuestas:


Eché un vistazo a la fuente de MVC para ver si podía averiguar cómo hacer esto. Parece haber un acoplamiento muy estrecho entre el contexto del controlador, las vistas, los datos de visualización, los datos de enrutamiento y los métodos de renderizado html.

Básicamente, para que esto suceda, debes crear todos estos elementos adicionales. Algunos de ellos son relativamente simples (como los datos de visualización) pero algunos son un poco más complejos, por ejemplo, los datos de enrutamiento considerarán que la página actual de WebForms se ignorará.

El gran problema parece ser el HttpContext: las páginas MVC se basan en una HttpContextBase (en lugar de HttpContext como WebForms) y, aunque ambas implementan IServiceProvider, no están relacionadas. Los diseñadores de MVC tomaron la decisión deliberada de no cambiar los WebForms heredados para usar la nueva base de contexto, sin embargo, sí proporcionaron un contenedor.

Esto funciona y le permite agregar una vista parcial a un 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 );
    }

}

Luego en su WebForm puede hacer esto:

<% WebFormMVCUtil.RenderPartial( "ViewName", this.GetModel() ); %>

93
2017-07-02 12:26



Me tomó un tiempo, pero encontré una gran solución. Como la solución Keith funciona para mucha gente, pero en ciertas situaciones no es la mejor, porque a veces quieres que tu aplicación pasar por el proceso del controlador para renderizar la vista, y La solución de Keith simplemente muestra la vista con un modelo dado Estoy presentando aquí una nueva solución que ejecutará el proceso normal.

Pasos generales:

  1. Crear una clase de utilidad
  2. Crea un controlador simulado con una vista ficticia
  3. En tus aspx o master page, llame al método de utilidad para hacer que pase parcialmente el Controlador, vea y, si lo necesita, el modelo para representar (como un objeto),

Veámoslo de cerca en este ejemplo

1) Crear una clase llamada MVCUtility y crea los siguientes métodos:

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

Cree una clase para pasar los parámetros, voy a llamar aquí RendeActionViewModel (puede crear en el mismo archivo de la clase MvcUtility)

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

2) Ahora crea un Controlador llamado DummyController

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

    }

Crear una vista simulada llamada PartialRender.cshtml (vista de la maquinilla de afeitar) para el DummyController con el siguiente contenido, tenga en cuenta que realizará otra acción de renderizado utilizando el helper Html

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

3) Ahora solo pon esto en tu MasterPage o aspx archivo, para renderizar parcialmente una vista que desee. Tenga en cuenta que esta es una gran respuesta cuando tiene varias vistas de maquinilla de afeitar que desea mezclar con su MasterPage o aspx páginas. (suponiendo que tenemos una Vista parcial llamada Inicio de sesión para el controlador Inicio

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

o si tienes un modelo para pasar a la Acción

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

Esta solución es genial, no usa una llamada ajax, que no causará un procesamiento retrasado para las vistas anidadas, doens no hace una nueva WebRequest por lo que no te traerá una nueva sesióny procesará el método para recuperar ActionResult para la vista que quieras, funciona sin pasar ningún modelo

Gracias a  Usando MVC RenderAction dentro de un formulario web


32
2017-07-21 14:06



la forma más obvia sería a través de AJAX

algo como esto (usando jQuery)

<div id="mvcpartial"></div>

<script type="text/javascript">
$(document).load(function () {
    $.ajax(
    {    
        type: "GET",
        url : "urltoyourmvcaction",
        success : function (msg) { $("#mvcpartial").html(msg); }
    });
});
</script>

20
2018-03-31 20:22



Esto es genial, gracias!

Estoy usando MVC 2 en .NET 4, que requiere que TextWriter pase a ViewContext, por lo que debe pasar httpContextWrapper.Response.Output como se muestra a continuación.

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

9
2017-09-12 21:11



Aquí hay un enfoque similar que me ha estado funcionando. La estrategia consiste en convertir la vista parcial en una cadena y luego generarla en la página 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();
    }
}

En el código de la página detrás, puede hacer

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

    }
}

y en la página tendrás acceso al contenido renderizado

<%= NavigationBarContent %>

¡Espero que ayude!


5
2017-08-14 07:04



Esta solución tiene un enfoque diferente. Define un System.Web.UI.UserControl que puede colocarse en cualquier formulario web y configurarse para mostrar el contenido desde cualquier URL ... incluida una vista parcial de MVC. Este enfoque es similar a una llamada AJAX para HTML en que los parámetros (si los hay) se dan a través de la cadena de consulta URL.

Primero, defina un control de usuario en 2 archivos:

/controls/PartialViewControl.ascx archivo

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

A continuación, agregue el control de usuario a su página de formulario 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/"  />

1
2018-06-10 23:05