Usando ChildActionOnly no MVC

168

Quando você usaria o atributo ChildActionOnly? O que é ChildActione em que circunstância você deseja restringir uma ação usando esse atributo?

Rafael Carvalho
fonte

Respostas:

161

O ChildActionOnlyatributo garante que um método de ação possa ser chamado apenas como método filho de dentro de uma visualização. Um método de ação não precisa ter esse atributo para ser usado como uma ação filho, mas tendemos a usá-lo para impedir que os métodos de ação sejam chamados como resultado de uma solicitação do usuário. Tendo definido um método de ação, precisamos criar o que será renderizado quando a ação for invocada. As ações filho geralmente estão associadas a visualizações parciais, embora isso não seja obrigatório.

  1. [ChildActionOnly] permitindo acesso restrito via código no modo de exibição

  2. Implementação de informações de estado para URL da página específica. Exemplo: a sintaxe do URL da página de pagamento (pagando apenas uma vez) permite chamar ações específicas condicionais

Tomasz Jaskuλa
fonte
Exemplo de uso em uma exibição: <% Html.RenderAction ("MyChildAction", "MyController"); %>. Assim, você não pode chamar uma ação criança com GET e roteamento
Erik Bergstedt
12
Código de exemplo: @ 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." Portanto, você evita um GET para um determinado controlador diretamente, mas apenas de outro controlador / ação. Provável: _Vistas parciais.
Langeleppel
1
Como capturar melhor InvalidOperationExceptionquando um método marcado <ChildActionOnly>é chamado pelo navegador?
Bernhard Döbler
Eu tive que usar @ Html.Action :)
chris c
125

Com o atributo [ChildActionOnly] anotado, um método de ação pode ser chamado apenas como método filho de uma exibição. Aqui está um exemplo para [ChildActionOnly]. .

existem dois métodos de ação: Index () e MyDateTime () e as Visualizações correspondentes: Index.cshtml e MyDateTime.cshtml. este é o 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);
    } 
}

Aqui está a visão para 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>

Aqui está a exibição parcial MyDateTime.cshtml .

@model DateTime

<p>
This is the child action result: @Model.ToLongTimeString()
<br />
@ViewBag.Message
</p>
 se você executar o aplicativo e fizer esta solicitação http: // localhost: 57803 / home / mydatetime
 O resultado será Erro do servidor da seguinte forma:

insira a descrição da imagem aqui

Isso significa que você não pode chamar diretamente a vista parcial. mas pode ser chamado pela visualização Index () como no Index.cshtml

     @ Html.Action ("MyDateTime") // Chamando a exibição parcial: MyDateTime ().
 

Se você remover [ChildActionOnly] e fizer a mesma solicitação http: // localhost: 57803 / home / mydatetime, ele permitirá obter o resultado da exibição parcial mydatetime:
This is the child action result. 12:53:31 PM 
This is from MyDateTime()
yantaq
fonte
eu acho que esta explicação era uma "paragem completa", graças homens
TAHA SULTAN Temuri
mas pode ser alcançado usando NonActiontambém, que diferença isso faz?
Imad
74

Você usaria se estiver usando RenderAction em qualquer uma das suas visualizações, geralmente para renderizar uma visualização parcial.

O motivo para marcá-lo [ChildActionOnly]é que você precisa que o método controller seja público para poder chamá-lo, RenderActionmas não deseja que alguém possa navegar para um URL (por exemplo, / Controller / SomeChildAction) e ver os resultados desse ação diretamente.

Eric Petroelje
fonte
2
semelhante a [NonAction]. é isso? qual é a diferença então?
DarthVader
10
@DarthVader - semelhante, mas com [não-ação] você não seria capaz de chamá-lo usando RenderActionqualquer um
Eric Petroelje
@EricPetroelje: Quais podem ser os benefícios de marcar o Método de Ação como NonActionAttributeem projetos reais?
wuhcwdc
1
@Pankaj - Honestamente, não consigo pensar em nenhuma razão realmente boa. Se você não deseja que um método em um controlador seja acessado por meio de uma URL, a melhor solução seria apenas fazer o método privateou protected. Eu realmente não posso pensar em nenhuma boa razão por que você iria querer fazer um método de controle public, exceto se você queria tanto ser capaz de chamá-lo diretamente ou viaRenderAction
Eric Petroelje
@ Eric: algumas vezes precisamos escrever um código pequeno para calcular, portanto, se isso é público no controlador, ele pode ser acessado pelo URL, se você não quiser que ele seja acessado por URL, marque-o como [NonAction ]
Ali Adravi
10

FYI, [ChildActionOnly] não está disponível no ASP.NET MVC Core. veja algumas informações aqui

Joseph Wu
fonte
8

Um pouco tarde para a festa, mas ...

As outras respostas explicam bem qual o efeito do [ChildActionOnly]atributo. No entanto, na maioria dos exemplos, fiquei me perguntando por que criaria um novo método de ação apenas para renderizar uma exibição parcial, dentro de outra, quando você poderia simplesmente renderizar@Html.Partial("_MyParialView") diretamente na exibição. Parecia uma camada desnecessária. No entanto, como investiguei, descobri que um benefício é que a ação filho pode criar um modelo diferente e transmiti-lo à visão parcial. O modelo necessário para a parcial pode não estar disponível no modelo da vista na qual a vista parcial está sendo renderizada. Em vez de modificar a estrutura do modelo para obter os objetos / propriedades necessários apenas para renderizar a vista parcial, você pode chamar a ação filho e solicitar que o método de ação crie o modelo necessário para a vista parcial.

Isso pode ser útil, por exemplo, em _Layout.cshtml. Se você tiver algumas propriedades comuns a todas as páginas, uma maneira de conseguir isso é usar um modelo de vista base e ter todos os outros modelos de vista herdados dele. Em seguida, é _Layoutpossível usar o modelo de vista base e as propriedades comuns. A desvantagem (que é subjetiva) é que todos os modelos de exibição devem herdar do modelo de exibição base para garantir que essas propriedades comuns estejam sempre disponíveis. A alternativa é renderizar @Html.Actionnesses lugares comuns. O método de ação criaria um modelo separado necessário para a visualização parcial comum a todas as páginas, o que não impactaria o modelo para a visualização "principal". Nesta alternativa, a _Layoutpágina não precisa ter um modelo. Daqui resulta que todos os outros modelos de vista não precisam herdar de nenhum modelo de vista base.

Tenho certeza de que existem outros motivos para usar o [ChildActionOnly]atributo, mas isso me parece bom, então pensei em compartilhar.

neizan
fonte
1
Outra vantagem é que, se uma chamada parcial é agrupada em uma chamada de ação, podemos adicionar um atributo de cache a ela.
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
fonte