Usando ChildActionOnly en MVC

168

¿Cuándo usarías el atributo ChildActionOnly? ¿Qué es ay ChildActionen qué circunstancias desearía restringir una acción utilizando este atributo?

Rafael Carvalho
fuente

Respuestas:

161

El ChildActionOnlyatributo garantiza que un método de acción se pueda invocar solo como un método secundario desde una vista. Un método de acción no necesita tener este atributo para usarse como una acción secundaria, pero tendemos a usar este atributo para evitar que los métodos de acción se invoquen como resultado de una solicitud del usuario. Habiendo definido un método de acción, necesitamos crear lo que se representará cuando se invoque la acción. Las acciones secundarias suelen asociarse con vistas parciales, aunque esto no es obligatorio.

  1. [ChildActionOnly] permitiendo acceso restringido a través del código en Ver

  2. Implementación de información de estado para URL de página específica. Ejemplo: la sintaxis de razor de URL de página de pago (pagando solo una vez) permite llamar a acciones específicas condicional

Tomasz Jaskuλa
fuente
Ejemplo de uso en una vista: <% Html.RenderAction ("MyChildAction", "MyController"); %>. Por lo tanto, no puede llamar a una acción secundaria con GET y enrutamiento
Erik Bergstedt
12
Código de ejemplo: @ Clark-Kent // example from Music Store // GET: /ShoppingCart/CartSummary [ChildActionOnly] public ActionResult CartSummary() { // your stuff } /ShoppingCart/CartSummary will return "The action 'CartSummary' is accessible only by a child request." Para evitar un GET a un determinado controlador directamente, pero solo desde otro controlador / acción. Probable: _Vistas parciales.
Langeleppel
1
¿Cómo atrapar mejor InvalidOperationExceptioncuando <ChildActionOnly>se llama a un Método marcado a través del navegador?
Bernhard Döbler
Tuve que usar @ Html.Action :)
chris c
125

Con el atributo [ChildActionOnly] anotado, un método de acción solo se puede invocar como un método secundario desde una vista. Aquí hay un ejemplo para [ChildActionOnly]. .

Hay dos métodos de acción: Index () y MyDateTime () y Vistas correspondientes: Index.cshtml y MyDateTime.cshtml. esto es HomeController.cs

public class HomeController : Controller
 {
    public ActionResult Index()
    {
        ViewBag.Message = "This is from Index()";
        var model = DateTime.Now;
        return View(model);
    }

    [ChildActionOnly]
    public PartialViewResult MyDateTime()
    {
        ViewBag.Message = "This is from MyDateTime()";

        var model = DateTime.Now;
        return PartialView(model);
    } 
}

Aquí está la vista de Index.cshtml .

@model DateTime
@{
    ViewBag.Title = "Index";
}
<h2>
    Index</h2>
<div>
    This is the index view for Home : @Model.ToLongTimeString()
</div>
<div>
    @Html.Action("MyDateTime")  // Calling the partial view: MyDateTime().
</div>

<div>
    @ViewBag.Message
</div>

Aquí está la vista parcial MyDateTime.cshtml .

@model DateTime

<p>
This is the child action result: @Model.ToLongTimeString()
<br />
@ViewBag.Message
</p>
 si ejecuta la aplicación y realiza esta solicitud http: // localhost: 57803 / home / mydatetime
 El resultado será un error del servidor así:

ingrese la descripción de la imagen aquí

Esto significa que no puede llamar directamente a la vista parcial. pero se puede llamar a través de la vista Index () como en el Index.cshtml

     @ Html.Action ("MyDateTime") // Llamando a la vista parcial: MyDateTime ().
 

Si elimina [ChildActionOnly] y realiza la misma solicitud http: // localhost: 57803 / home / mydatetime, le permite obtener el resultado de la vista parcial de mydatetime:
This is the child action result. 12:53:31 PM 
This is from MyDateTime()
yantaq
fuente
Creo que esta explicación fue un "punto final", gracias hombres
TAHA SULTAN TEMURI
pero se puede lograr usando NonActiontambién, ¿qué diferencia hace?
Imad
74

Lo usaría si está utilizando RenderActioncualquiera de sus vistas, generalmente para representar una vista parcial.

La razón para marcarlo [ChildActionOnly]es que necesita que el método del controlador sea público para poder llamarlo, RenderActionpero no desea que alguien pueda navegar a una URL (por ejemplo, / Controller / SomeChildAction) y ver los resultados. acción directa

Eric Petroelje
fuente
2
similar a [No acción]. ¿Lo es? ¿Cuál es la diferencia entonces?
DarthVader
10
@DarthVader - similares, pero con [no-acción] que no sería capaz de llamar usando RenderActionya sea
Eric Petroelje
@EricPetroelje: ¿Cuáles pueden ser los beneficios de marcar el Método de acción como NonActionAttributeen proyectos reales?
wuhcwdc
1
@ Pankaj - Honestamente, no puedo pensar en ninguna razón realmente buena. Si no desea que se acceda a un método en un controlador a través de una URL, la mejor solución sería hacer el método privateo protected. Realmente no puedo pensar en ninguna buena razón por la que se quiere hacer un método de control public, excepto si desea ser capaz de llamar directamente o por medio deRenderAction
Eric Petroelje
@Eric: algunas veces necesitamos escribir un código pequeño para calcular, por lo que si eso es público en el controlador, entonces se puede acceder por la URL, si no desea que se acceda por URL, márquelo como [No acción ]
Ali Adravi
10

Para su información, [ChildActionOnly] no está disponible en ASP.NET MVC Core. ver información aquí

Joseph Wu
fuente
8

Un poco tarde para la fiesta, pero ...

Las otras respuestas hacen un buen trabajo al explicar qué efecto tiene el [ChildActionOnly]atributo. Sin embargo, en la mayoría de los ejemplos, seguí preguntándome por qué crearía un nuevo método de acción solo para representar una vista parcial, dentro de otra vista, cuando simplemente podría renderizar @Html.Partial("_MyParialView")directamente en la vista. Parecía una capa innecesaria. Sin embargo, mientras investigaba, descubrí que un beneficio es que la acción del niño puede crear un modelo diferente y pasarlo a la vista parcial. El modelo necesario para el parcial podría no estar disponible en el modelo de la vista en la que se representa la vista parcial. En lugar de modificar la estructura del modelo para obtener los objetos / propiedades necesarios allí solo para representar la vista parcial, puede llamar a la acción secundaria y hacer que el método de acción se encargue de crear el modelo necesario para la vista parcial.

Esto puede ser útil, por ejemplo, en _Layout.cshtml. Si tiene algunas propiedades comunes a todas las páginas, una forma de lograr esto es usar un modelo de vista base y hacer que todos los demás modelos de vista hereden de él. Luego, _Layoutpuede usar el modelo de vista base y las propiedades comunes. La desventaja (que es subjetiva) es que todos los modelos de vista deben heredar del modelo de vista base para garantizar que esas propiedades comunes estén siempre disponibles. La alternativa es renderizar @Html.Actionen esos lugares comunes. El método de acción crearía un modelo separado necesario para la vista parcial común a todas las páginas, lo que no afectaría el modelo para la vista "principal". En esta alternativa, la _Layoutpágina no necesita tener un modelo. Se deduce que todos los demás modelos de vista no necesitan heredar de ningún modelo de vista base.

Estoy seguro de que hay otras razones para usar el [ChildActionOnly]atributo, pero esto me parece bueno, así que pensé en compartirlo.

neizan
fuente
1
Otra ventaja es que si una llamada parcial se envuelve en una llamada a la acción, entonces podemos agregarle un atributo de caché.
kamgman
0
    public class HomeController : Controller  
    {  
        public ActionResult Index()  
        {  
            ViewBag.TempValue = "Index Action called at HomeController";  
            return View();  
        }  

        [ChildActionOnly]  
        public ActionResult ChildAction(string param)  
        {  
            ViewBag.Message = "Child Action called. " + param;  
            return View();  
        }  
    }  


The code is initially invoking an Index action that in turn returns two Index views and at the View level it calls the ChildAction named ChildAction”.

    @{
        ViewBag.Title = "Index";    
    }    
    <h2>    
        Index    
    </h2>  

    <!DOCTYPE html>    
    <html>    
    <head>    
        <title>Error</title>    
    </head>    
    <body>    
        <ul>  
            <li>    
                @ViewBag.TempValue    
            </li>    
            <li>@ViewBag.OnExceptionError</li>    
            @*<li>@{Html.RenderAction("ChildAction", new { param = "first" });}</li>@**@    
            @Html.Action("ChildAction", "Home", new { param = "first" })    
        </ul>    
    </body>    
    </html>  


      Copy and paste the code to see the result .thanks 
Hamid Nawaz
fuente