Korzystanie z ChildActionOnly w MVC

168

Kiedy użyjesz atrybutu ChildActionOnly? Co to jest ChildActioni w jakich okolicznościach chcesz ograniczyć działanie za pomocą tego atrybutu?

Rafael Carvalho
źródło

Odpowiedzi:

161

ChildActionOnlyAtrybut zapewnia, że metoda działania można nazwać tylko jako sposób dziecko od wewnątrz widoku. Metoda akcji nie musi mieć tego atrybutu, aby była używana jako akcja podrzędna, ale zwykle używamy tego atrybutu, aby zapobiec wywoływaniu metod akcji w wyniku żądania użytkownika. Po zdefiniowaniu metody akcji musimy stworzyć to, co będzie renderowane, gdy akcja zostanie wywołana. Działania dzieci są zwykle związane z częściowymi poglądami, chociaż nie jest to obowiązkowe.

  1. [ChildActionOnly] zezwalające na ograniczony dostęp za pomocą kodu w widoku

  2. Implementacja informacji o stanie dla określonego adresu URL strony. Przykład: URL strony płatności (płacąc tylko raz) składnia maszynki do golenia umożliwia wywołanie określonych akcji jako warunkowe

Tomasz Jaskuλa
źródło
Przykładowe użycie w widoku: <% Html.RenderAction ("MyChildAction", "MyController"); %>. Dlatego nie możesz wywołać akcji dziecka za pomocą GET i routingu
Erik Bergstedt
12
Przykładowy kod: @ 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." Więc uniemożliwiasz GET bezpośrednio do określonego kontrolera, ale tylko z innego kontrolera / akcji. Prawdopodobnie: _ Częściowe wyświetlenia.
Langeleppel
1
Jak najlepiej wychwycić, InvalidOperationExceptionkiedy zaznaczona metoda <ChildActionOnly>jest wywoływana przez przeglądarkę?
Bernhard Döbler,
Musiałem użyć @ Html.Action :)
chris c
125

W przypadku atrybutu [ChildActionOnly] z adnotacją metodę akcji można wywołać tylko jako metodę podrzędną z poziomu widoku. Oto przykład dla [ChildActionOnly]. .

istnieją dwie metody akcji: Index () i MyDateTime () oraz odpowiadające im widoki: Index.cshtml i MyDateTime.cshtml. to jest 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);
    } 
}

Oto widok pliku 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>

Oto częściowy widok MyDateTime.cshtml .

@model DateTime

<p>
This is the child action result: @Model.ToLongTimeString()
<br />
@ViewBag.Message
</p>
 jeśli uruchomisz aplikację i wykonasz to żądanie http: // localhost: 57803 / home / mydatetime
 Rezultatem będzie błąd serwera w następujący sposób:

wprowadź opis obrazu tutaj

Oznacza to, że nie możesz bezpośrednio wywołać częściowego widoku. ale można go wywołać za pomocą widoku Index (), tak jak w pliku Index.cshtml

     @ Html.Action ("MyDateTime") // Wywołanie częściowego widoku: MyDateTime ().
 

Jeśli usuniesz [ChildActionOnly] i wykonasz to samo żądanie http: // localhost: 57803 / home / mydatetime, pozwoli to uzyskać wynik częściowego widoku mydatetime:
This is the child action result. 12:53:31 PM 
This is from MyDateTime()
yantaq
źródło
myślę, że to wyjaśnienie było „
kropką
ale można to osiągnąć NonActionrównież, co to za różnica?
Imad
74

Użyjesz go, jeśli używasz RenderActionw którymkolwiek ze swoich widoków, zwykle do renderowania widoku częściowego.

Powodem oznaczenia tego [ChildActionOnly]jest to, że potrzebujesz metody kontrolera, aby była publiczna, więc możesz ją wywołać, RenderActionale nie chcesz, aby ktoś mógł przejść do adresu URL (np. / Controller / SomeChildAction) i zobaczyć wyniki tego działanie bezpośrednio.

Eric Petroelje
źródło
2
podobny do [NonAction]. czy to jest jaka jest więc różnica?
DarthVader,
10
@DarthVader - Podobnie, ale z [NonAction] nie byłbyś w stanie zadzwonić do tego za pomocą RenderActionżadnego
Eric Petroelje
@EricPetroelje: Jakie mogą być korzyści z oznaczania metody działania jako NonActionAttributerzeczywistych projektów?
wuhcwdc
1
@Pankaj - Szczerze mówiąc, nie przychodzi mi do głowy żaden naprawdę dobry powód. Jeśli nie chcesz, aby dostęp do metody na kontrolerze był możliwy za pośrednictwem adresu URL, najlepszym rozwiązaniem byłoby po prostu utworzenie metody privatelub protected. Naprawdę nie mogę wymyślić żadnego dobrego powodu, dla którego chciałbyś stworzyć metodę kontrolera, publicchyba że chciałbyś mieć możliwość wywołania jej bezpośrednio lub przezRenderAction
Eric Petroelje
@Eric: czasami musimy napisać mały kod do obliczenia, więc jeśli jest on publiczny w kontrolerze, można uzyskać do niego dostęp za pomocą adresu URL, jeśli w ogóle nie chcesz, aby był on dostępny przez adres URL, oznacz go jako [NonAction ]
Ali Adravi
10

FYI, [ChildActionOnly] nie jest dostępne w ASP.NET MVC Core. zobacz więcej informacji tutaj

Joseph Wu
źródło
8

Trochę za późno na imprezę, ale ...

Pozostałe odpowiedzi dobrze wyjaśniają, jaki wpływ [ChildActionOnly]ma ten atrybut. Jednak w większości przykładów ciągle zadawałem sobie pytanie, dlaczego tworzyłem nową metodę akcji tylko po to, aby renderować częściowy widok w innym widoku, skoro można po prostu renderować @Html.Partial("_MyParialView")bezpośrednio w widoku. Wydawało się, że jest to niepotrzebna warstwa. Jednak, gdy badałem, odkryłem, że jedną z korzyści jest to, że działanie dziecka może stworzyć inny model i przekazać go częściowemu poglądowi. Model potrzebny dla częściowej może nie być dostępny w modelu widoku, w którym renderowany jest widok częściowy. Zamiast modyfikować strukturę modelu, aby uzyskać potrzebne obiekty / właściwości tylko do renderowania częściowego widoku, możesz wywołać akcję potomną i zlecić metodzie akcji utworzenie modelu potrzebnego do widoku częściowego.

Może się to przydać na przykład w _Layout.cshtml. Jeśli masz kilka właściwości wspólnych dla wszystkich stron, jednym ze sposobów osiągnięcia tego jest użycie modelu widoku bazowego i dziedziczenie z niego wszystkich innych modeli widoku. Następnie _Layoutmoże użyć modelu widoku bazowego i wspólnych właściwości. Wadą (która jest subiektywna) jest to, że wszystkie modele widoków muszą dziedziczyć z modelu widoku podstawowego, aby zagwarantować, że te wspólne właściwości są zawsze dostępne. Alternatywą jest renderowanie @Html.Actionw tych wspólnych miejscach. Metoda akcji stworzyłaby oddzielny model potrzebny dla częściowego widoku wspólnego dla wszystkich stron, co nie wpłynęłoby na model dla „głównego” widoku. W tym przypadku _Layoutstrona nie musi mieć modelu. Wynika z tego, że wszystkie inne modele widoku nie muszą dziedziczyć z żadnego modelu widoku bazowego.

Jestem pewien, że istnieją inne powody, dla których warto używać tego [ChildActionOnly]atrybutu, ale wydaje mi się, że jest to dobry, więc pomyślałem, że się nim podzielę.

neizan
źródło
1
Kolejną zaletą jest to, że jeśli częściowe wywołanie jest opakowane w wywołanie akcji, możemy dodać do niego atrybut 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
źródło