Utilisation de ChildActionOnly dans MVC

168

Quand utiliseriez-vous l'attribut ChildActionOnly? Qu'est-ce qu'un ChildActionet dans quelles circonstances voudriez-vous restreindre une action à l'aide de cet attribut?

Rafael Carvalho
la source

Réponses:

161

L' ChildActionOnlyattribut garantit qu'une méthode d'action ne peut être appelée qu'en tant que méthode enfant à partir d'une vue. Une méthode d'action n'a pas besoin d'avoir cet attribut pour être utilisée comme action enfant, mais nous avons tendance à utiliser cet attribut pour empêcher les méthodes d'action d'être appelées à la suite d'une demande utilisateur. Après avoir défini une méthode d'action, nous devons créer ce qui sera rendu lorsque l'action est appelée. Les actions enfants sont généralement associées à des vues partielles, bien que ce ne soit pas obligatoire.

  1. [ChildActionOnly] autorisant un accès restreint via un code dans View

  2. Implémentation des informations d'état pour une URL de page spécifique. Exemple: la syntaxe de l'URL de la page de paiement (payant une seule fois) permet d'appeler des actions spécifiques de manière conditionnelle

Tomasz Jaskuλa
la source
Exemple d'utilisation dans une vue: <% Html.RenderAction ("MyChildAction", "MyController"); %>. Ainsi, vous ne pouvez pas appeler une action enfant avec GET et le routage
Erik Bergstedt
12
Exemple de code: @ 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." Ainsi, vous empêchez un GET vers un certain contrôleur directement, mais uniquement depuis un autre contrôleur / action. Probablement: vues partielles.
Langeleppel
1
Comment savoir au mieux InvalidOperationExceptionquand une méthode marquée <ChildActionOnly>est appelée via le navigateur?
Bernhard Döbler
J'ai dû utiliser @ Html.Action :)
chris c
125

Avec l' attribut [ChildActionOnly] annoté, une méthode d'action ne peut être appelée qu'en tant que méthode enfant à partir d'une vue. Voici un exemple pour [ChildActionOnly]. .

il existe deux méthodes d'action: Index () et MyDateTime () et les vues correspondantes: Index.cshtml et MyDateTime.cshtml. c'est 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);
    } 
}

Voici la vue pour 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>

Voici la vue partielle de MyDateTime.cshtml .

@model DateTime

<p>
This is the child action result: @Model.ToLongTimeString()
<br />
@ViewBag.Message
</p>
 si vous exécutez l'application et faites cette demande http: // localhost: 57803 / home / mydatetime
 Le résultat sera une erreur de serveur comme ceci:

entrez la description de l'image ici

Cela signifie que vous ne pouvez pas appeler directement la vue partielle. mais il peut être appelé via la vue Index () comme dans Index.cshtml

     @ Html.Action ("MyDateTime") // Appel de la vue partielle: MyDateTime ().
 

Si vous supprimez [ChildActionOnly] et faites la même requête http: // localhost: 57803 / home / mydatetime, cela vous permet d'obtenir le résultat de la vue partielle mydatetime:
This is the child action result. 12:53:31 PM 
This is from MyDateTime()
yantaq
la source
Je pense que cette explication était un "point
final
mais il peut être réalisé en utilisant NonActionaussi, quelle différence cela fait-il?
Imad
74

Vous l'utiliseriez si vous l'utilisez RenderActiondans l'une de vos vues, généralement pour rendre une vue partielle.

La raison de le marquer avec [ChildActionOnly]est que vous avez besoin que la méthode du contrôleur soit publique afin que vous puissiez l'appeler avec, RenderActionmais vous ne voulez pas que quelqu'un puisse naviguer vers une URL (par exemple / Controller / SomeChildAction) et voir les résultats de cela action directe.

Eric Petroelje
la source
2
similaire à [NonAction]. c'est ça? quelle est la différence alors?
DarthVader
10
@DarthVader - Similaire, mais avec [NonAction] vous ne pourrez pas l'appeler en utilisant l'un RenderActionou l'autre
Eric Petroelje
@EricPetroelje: Quels peuvent être les avantages de marquer la méthode d'action comme NonActionAttributedans de vrais projets?
wuhcwdc
1
@Pankaj - Honnêtement, je ne peux pas penser à de très bonnes raisons. Si vous ne voulez pas qu'une méthode sur un contrôleur soit accessible via une URL, la meilleure solution serait simplement de créer la méthode privateou protected. Je ne peux pas vraiment penser à une bonne raison pour laquelle vous voudriez créer une méthode de contrôleur, publicsauf si vous vouliez pouvoir l'appeler directement ou viaRenderAction
Eric Petroelje
@Eric: parfois, nous devons écrire un petit code pour calculer, donc si cela est public dans le contrôleur, il peut être consulté par l'URL, si vous ne voulez pas du tout qu'il soit accessible par URL, marquez-le comme [NonAction ]
Ali Adravi
10

Pour info, [ChildActionOnly] n'est pas disponible dans ASP.NET MVC Core. voir quelques infos ici

Joseph Wu
la source
8

Un peu tard à la fête, mais ...

Les autres réponses expliquent bien l'effet de l' [ChildActionOnly]attribut. Cependant, dans la plupart des exemples, je n'arrêtais pas de me demander pourquoi je créerais une nouvelle méthode d'action juste pour rendre une vue partielle, dans une autre vue, alors que vous pouviez simplement effectuer @Html.Partial("_MyParialView")un rendu directement dans la vue. Cela semblait être une couche inutile. Cependant, en enquêtant, j'ai trouvé qu'un avantage est que l'action enfant peut créer un modèle différent et le transmettre à la vue partielle. Le modèle nécessaire pour le partiel peut ne pas être disponible dans le modèle de la vue dans laquelle la vue partielle est rendue. Au lieu de modifier la structure du modèle pour y obtenir les objets / propriétés nécessaires juste pour rendre la vue partielle, vous pouvez appeler l'action enfant et demander à la méthode d'action de créer le modèle nécessaire pour la vue partielle.

Cela peut être utile, par exemple, dans _Layout.cshtml. Si vous avez quelques propriétés communes à toutes les pages, une façon d'y parvenir est d'utiliser un modèle de vue de base et d'en hériter tous les autres modèles de vue. Ensuite, le _Layoutpeut utiliser le modèle de vue de base et les propriétés communes. L'inconvénient (qui est subjectif) est que tous les modèles de vue doivent hériter du modèle de vue de base pour garantir que ces propriétés communes sont toujours disponibles. L'alternative est de rendre @Html.Actiondans ces lieux communs. La méthode d'action créerait un modèle distinct nécessaire pour la vue partielle commune à toutes les pages, ce qui n'aurait pas d'impact sur le modèle de la vue "principale". Dans cette alternative, la _Layoutpage n'a pas besoin d'avoir un modèle. Il s'ensuit que tous les autres modèles de vue n'ont pas besoin d'hériter d'un modèle de vue de base.

Je suis sûr qu'il y a d'autres raisons d'utiliser l' [ChildActionOnly]attribut, mais cela me semble être une bonne raison, alors j'ai pensé partager.

Neizan
la source
1
Un autre avantage est que si un appel partiel est encapsulé dans un appel d'action, nous pouvons lui ajouter un attribut de cache.
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
la source