Renderizar parcial desde una carpeta diferente (no compartida)

256

¿Cómo puedo hacer que una vista represente un parcial (control de usuario) desde una carpeta diferente? Con la vista previa 3 solía llamar a RenderUserControl con la ruta completa, pero con la actualización a la vista previa 5 esto ya no es posible. En cambio, obtuvimos el método RenderPartial, pero no me ofrece la funcionalidad que estoy buscando.

Boris Callens
fuente

Respuestas:

443

Simplemente incluya la ruta a la vista, con la extensión del archivo.

Maquinilla de afeitar:

@Html.Partial("~/Views/AnotherFolder/Messages.cshtml", ViewData.Model.Successes)

Motor ASP.NET:

<% Html.RenderPartial("~/Views/AnotherFolder/Messages.ascx", ViewData.Model.Successes); %>

Si ese no es su problema, ¿podría incluir su código que solía funcionar con RenderUserControl?

Elijah Manor
fuente
19
Ojalá pudiéramos decir / AnotherFolder / Messages
Simon_Weaver
44
@Simon_Weaver Puedes lograr eso. Una forma sería modificar ViewEngine y anular su FindPartialViewmétodo con algo comoif(partialViewName.Contains"/")partialViewName="~/Views/"+partialViewName;
Arnis Lapsa
2
También funciona en el motor MVC 3 Razor, pero al igual que lo anterior, necesita la extensión (.cshtml).
Chris
Si está bajo diferente, necesitaría dar la ruta "~ / Areas / TestArea / Views / Shared / _SomePartial.mobile.cshtml"
sandeep talabathula
¿Cómo maneja las diferentes culturas de esa vista parcial (por ejemplo ~ / Views / AnotherFolder / Messages.en.cshtml)?
jasdefer
29

En mi caso, estaba usando MvcMailer (https://github.com/smsohan/MvcMailer) y quería acceder a una vista parcial desde otra carpeta, que no estaba en "Shared". Las soluciones anteriores no funcionaron, pero el uso de una ruta relativa sí.

@Html.Partial("../MyViewFolder/Partials/_PartialView", Model.MyObject)
Aaron Sherman
fuente
Del mismo modo, @ Html.Partial ("../ Shared / _PartialView") para usar la carpeta Shared.
Curtis Yallop
11
Estoy descubriendo que esto no funciona sin la extensión .cshtml al final.
Lucas
28

Si usa esta otra ruta la mayor parte del tiempo, puede arreglarla permanentemente sin tener que especificar la ruta todo el tiempo. De forma predeterminada, está buscando vistas parciales en la carpeta Ver y en la carpeta Compartida. Pero di que quieres agregar uno.

Agregue una clase a su carpeta Modelos:

public class NewViewEngine : RazorViewEngine {

   private static readonly string[] NEW_PARTIAL_VIEW_FORMATS = new[] {
      "~/Views/Foo/{0}.cshtml",
      "~/Views/Shared/Bar/{0}.cshtml"
   };

   public NewViewEngine() {
      // Keep existing locations in sync
      base.PartialViewLocationFormats = base.PartialViewLocationFormats.Union(NEW_PARTIAL_VIEW_FORMATS).ToArray();
   }
}

Luego, en su archivo Global.asax.cs, agregue la siguiente línea:

ViewEngines.Engines.Add(new NewViewEngine());
Pablo
fuente
66
Por supuesto, me doy cuenta de que esta pregunta se hizo hace mucho tiempo. Pensé en agregarlo para futuros Googlers y futuros Bingers.
Paul
- No funcionará en .Net Core 2.2, ya que RazorViewEngine.PartialViewLocationFormats no existe.
Demian Berisford-Maynard
7

Para un control de usuario llamado myPartial.ascx ubicado en la carpeta Vistas / Cuenta, escriba así:

<%Html.RenderPartial("~/Views/Account/myPartial.ascx");%>
Rahatur
fuente
5

He creado una solución alternativa que parece estar funcionando bastante bien. Encontré la necesidad de cambiar al contexto de un controlador diferente para la búsqueda de nombre de acción, búsqueda de vista, etc. Para implementar esto, creé un nuevo método de extensión para HtmlHelper:

public static IDisposable ControllerContextRegion(
    this HtmlHelper html, 
    string controllerName)
{
    return new ControllerContextRegion(html.ViewContext.RouteData, controllerName);
}

ControllerContextRegion Se define como:

internal class ControllerContextRegion : IDisposable
{
    private readonly RouteData routeData;
    private readonly string previousControllerName;

    public ControllerContextRegion(RouteData routeData, string controllerName)
    {
        this.routeData = routeData;
        this.previousControllerName = routeData.GetRequiredString("controller");
        this.SetControllerName(controllerName);
    }

    public void Dispose()
    {
        this.SetControllerName(this.previousControllerName);
    }

    private void SetControllerName(string controllerName)
    {
        this.routeData.Values["controller"] = controllerName;
    }
}

La forma en que se usa dentro de una vista es la siguiente:

@using (Html.ControllerContextRegion("Foo")) {
    // Html.Action, Html.Partial, etc. now looks things up as though
    // FooController was our controller.
}

Puede haber efectos secundarios no deseados para esto si su código requiere que el controllercomponente de ruta no cambie, pero en nuestro código hasta ahora, no parece haber ningún aspecto negativo en este enfoque.

Jacob
fuente
4

Se supone que VirtualPathProviderViewEngine, en el que se basa WebFormsViewEngine, admite los caracteres "~" y "/" en la parte frontal de la ruta, por lo que sus ejemplos anteriores deberían funcionar.

Noté que sus ejemplos usan la ruta "~ / Account / myPartial.ascx", pero usted mencionó que su control de usuario está en la carpeta Vistas / Cuenta. Has probado

<%Html.RenderPartial("~/Views/Account/myPartial.ascx");%>

o es solo un error tipográfico en tu pregunta?

Andrew Stanton-Enfermera
fuente
0

deberías probar esto

~/Views/Shared/parts/UMFview.ascx

coloque el ~/Views/antes de su código

mounir
fuente
0

Cree un motor de vista personalizado y tenga un método que devuelva un ViewEngineResult. En este ejemplo, simplemente sobrescribe _options.ViewLocationFormatsy agrega el directorio de su carpeta:

public ViewEngineResult FindView(ActionContext context, string viewName, bool isMainPage)
        {
            var controllerName = context.GetNormalizedRouteValue(CONTROLLER_KEY);
            var areaName = context.GetNormalizedRouteValue(AREA_KEY);

            var checkedLocations = new List<string>();
            foreach (var location in _options.ViewLocationFormats)
            {
                var view = string.Format(location, viewName, controllerName);
                if (File.Exists(view))
                {
                    return ViewEngineResult.Found("Default", new View(view, _ViewRendering));
                }
                checkedLocations.Add(view);
            }

            return ViewEngineResult.NotFound(viewName, checkedLocations);
        }

Ejemplo: https://github.com/AspNetMonsters/pugzor

Demian Berisford-Maynard
fuente
-5

Intenta usar RenderAction("myPartial","Account");

Siva Kandaraj
fuente
3
Lea la pregunta mientras el usuario pregunta sobre la vista en una carpeta diferente, ¿dónde está la carpeta en su código?
Pamma