Pregunta

Algunos sitio Estoy programación está utilizando tanto ASP.NET MVC y WebForms.

Tengo una visión parcial y quiero incluir esto dentro de una formulario web. La vista parcial tiene un código que tiene que ser procesado en el servidor, por lo que usar Response.WriteFile no funcionan. Se debe trabajar con JavaScript desactivado.

¿Cómo puedo hacer esto?

¿Fue útil?

Solución

Yo tenía un vistazo a la fuente MVC para ver si podía encontrar la manera de hacer esto. Parece que hay muy cerca de acoplamiento entre el contexto controlador, vistas, Vista de datos, datos de encaminamiento y el html render métodos.

Básicamente con el fin de hacer que esto suceda es necesario crear todos estos elementos adicionales. Algunos de ellos son relativamente simples (como los datos de la vista), pero algunos son un poco más complejo -., Por ejemplo, los datos de enrutamiento tendrá en cuenta la página de formularios Web actuales que se ignore

El gran problema parece ser el HttpContext - MVC páginas se basan en un HttpContextBase (en lugar de HttpContext como WebForms hacer) y mientras tanto poner en práctica IServiceProvider que no están relacionados entre sí. Los diseñadores de MVC tomaron una decisión deliberada de no cambiar los formularios Web de legado a utilizar la nueva base de contexto, sin embargo, proporcionaban una envoltura.

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

}

A continuación, en su formulario Web puede hacer esto:

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

Otros consejos

Me tomó un tiempo, pero he encontrado una gran solución. La solución de Keith trabaja para una gran cantidad de personas, pero en ciertas situaciones que no es la mejor, porque a veces desea que la aplicación que pasar por el proceso del controlador para renderizar la vista, y la solución de Keith simplemente hace que la vista con un modelo dado que estoy presentando aquí una nueva solución que va a ejecutar el proceso normal.

Pasos generales:

  1. Crea una clase de utilidad
  2. Crear un controlador de Maniquí con una visión ficticia
  3. En su aspx o master page, llame al método de utilidad para hacer pasar el controlador parcial, ver y si es necesario, el modelo de representación (como objeto),

Vamos a ver de cerca en este ejemplo

1) Crear un MVCUtility clase llamada y crear los métodos siguientes:

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

Crear una clase para pasar los parámetros, que llamaré aquí RendeActionViewModel (que 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 crear un controlador llamado DummyController

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

Crea una vista simulada llamada PartialRender.cshtml (vista de afeitar) para la DummyController con el siguiente contenido, tenga en cuenta que se llevará a cabo otra inutilidad la actuación mediante el asistente de HTML.

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

3) Ahora sólo hay que poner esto en su archivo MasterPage o aspx, para rendir un parcial vista que desea. Tenga en cuenta que esta es una gran respuesta cuando se tienen varios puntos de vista de afeitar que desea mezclar con las páginas MasterPage o aspx. (Suponiendo que tenemos una llamada PartialView Acceder al controlador de Inicio).

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

o si tiene un modelo para pasar a la acción

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

Esta solución es grande, no utiliza ajax llamada , que no provocará una retrasada rendir para las vistas anidadas, que no hace nueva WebRequest para que no le traerá una nueva sesión , y procesará el método para recuperar el ActionResult de la vista que desee, funciona sin pasar cualquier modelo

Gracias a Uso de MVC RenderAction dentro de un Webform

manera 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>

Esto es muy bueno, gracias!

Estoy usando MVC 2 en .NET 4, que requiere un TextWriter se pasa a la ViewContext, por lo que tiene que pasar en 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);
    }

Aquí hay un enfoque similar que ha estado trabajando para mí. La estrategia consiste en hacer que la vista parcial de una cadena, entonces la salida que en la página de formulario 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();
    }
}

En la página de código subyacente, que 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á acceso al contenido representado

<%= NavigationBarContent %>

Espero que ayude!

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

En primer lugar, definir 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, añadir el control de usuario a la 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/"  />

Fwiw, necesitaba ser capaz de rendir una vista parcial dinámicamente a partir de código de formularios web existente, y la inserta en la parte superior de un control dado. He encontrado que la respuesta de Keith puede hacer que la visión parcial que pasarán a ser fuera de la etiqueta <html />.

Uso de las respuestas de Keith y Hilarius en busca de inspiración, en lugar de representación directa a HttpContext.Current.Response.Output, I emitió la cadena HTML y añadió como un LiteralControl al control correspondiente.

En clase auxiliar estática:

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

En la clase llamando a:

    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);
    }
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top