Este artigo foi traduzido por máquina.

table.one { table-layout:fixed;width: 900px; font-size: 14px; color: #333; margin-bottom: 5px; } table.two { table-layout:fixed;width: 600px; border-top: 3px; border-top-color: #0569b5; border-top-style:solid; margin-bottom: 10px; } .tdwidth{ width:400px; } .tdwidth1{ width: 220px; } .SidebarInsights { border: 2px solid #008080; padding: 10px 20px 20px 20px; background-color: #e1e8f5; margin: 10px 0px 10px 0px; font-family: Verdana, Arial; font-size: 12px; padding-bottom: 7px; line-height: 16px; color: #333333; }

ASP.NET extremo

A vida E períodos de um controlador de MVC do ASP.NET

Scott Allen

Download do código disponível na Galeria de código do MSDN
Procure o código on-line

Este artigo se baseia em uma versão pré-lançamento do Framework de MVC ASP.NET. Detalhes estão sujeitos a alterações.

Conteúdo

Todas as rotas permitir uma fábrica
Extensibilidade de fábrica
Execução É apenas o início
Seletor de atributos
Atributos de filtro
Filtros de ação personalizada
Obtendo resultados
A ação está em

Os controladores são os lynchpins do design padrão MVC (Model View controlador). Eles são na linha de frente, primeiro receber solicitações de um cliente e, em seguida, convertendo as solicitações em instruções para o modelo de onde a lógica de domínio do aplicativo e os dados residem. Controladores também são responsáveis por selecionar um modo de exibição para apresentar informações para o usuário.

Neste artigo, VOU vejamos a estrutura do ASP.NET MVC e veja como funcionam os controladores. Explicarei como a estrutura interage com os controladores e como você pode influenciar as interações. Examinarei fábricas de controlador, ações de controlador, filtros de ação e os resultados de ação.

Será Examine em bastante profundamente, portanto, se você estiver procurando uma introdução mais geral para a estrutura MVC do ASP.NET, consulte o artigo dos Chris Tavares"Criação de aplicativos sem formulários da Web Web."

Todas as rotas permitir uma fábrica

É difícil falar sobre a vida útil de um controlador sem falar sobre roteiros. A tabela de roteamento em um aplicativo ASP.NET contém as informações necessárias para o módulo de roteamento do ASP.NET para extrair informações de uma URL de entrada e direcionar a solicitação para o componente de software apropriado. Na coluna de janeiro, examinamos usando o módulo de roteamento do ASP.NET com Web Forms "Roteamento com formulários da Web do ASP.NET".) Na coluna, criei meu próprio manipulador de roteamento para executar um formulário da Web, mas a estrutura MVC ASP.NET oferece um manipulador de roteamento que eventualmente direcionará uma solicitação para um dos nossos controladores.

Para esse manipulador de roteamento MVC para processar solicitações, você precisará configurar a tabela de roteamento durante a inicialização do aplicativo. A configuração de roteamento padrão fornecida pelo modelo de projeto MVC vive no arquivo global.asax e é mostrada na Figura 1 .

Figura 1 A configuração de roteamento padrão

public static void RegisterRoutes(RouteCollection routes)
{
    routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

    routes.MapRoute(
        "Default",                                             
        "{controller}/{action}/{id}",                          
        new { controller = "Home", action = "Index", id = "" } 
    );            

}

protected void Application_Start()
{
    RegisterRoutes(RouteTable.Routes);
}

Uma das entradas configuração roteamento na Figura 1 é uma rota denominada padrão com um modelo de URL de " {controlador} / {ação} / {id} ". Este modelo de URL é um padrão que o mecanismo de roteamento usará para ver primeiro se um URL de entrada for uma correspondência para esta rota. Uma URL que deve corresponder a uma rota seria http://localhost/home/index/. Quando o mecanismo de roteamento encontra uma correspondência, ele irá usar novamente o modelo de URL como um padrão para levantar parâmetros da URL de entrada. Neste exemplo, a seqüência de caracteres doméstica se torna o parâmetro de controlador porque ele é na posição {controlador}, e a seqüência de caracteres "índice" torna-se o parâmetro de ação.

O objeto anonimamente digitado construído como terceiro parâmetro para MapRoute representa os valores padrão para o mecanismo de roteamento usar se não consegue localizar um determinado parâmetro na URL. No caso do http://localhost/home/index/, o mecanismo de roteamento não localizar informações de "ID" no URL, mas ainda passará ao longo de um parâmetro de id com o valor padrão de uma seqüência vazia. O mecanismo de roteamento passa esses parâmetros para um manipulador de roteamento por meio de um objeto RouteData.

É importante observar que o mecanismo de roteamento sabe nada sobre MVC do ASP.NET. Somente tarefa o mecanismo é analisar URLs e passar controle para um manipulador de roteiro. O método de MapRoute ser invocado dentro do método RegisterRoutes da Figura 1 é um método de extensão fornecido pelo framework MVC. Cada rota registrada com MapRoute está configurada para usar um objeto MvcRouteHandler — isso é o manipulador de rota fornecido pelo framework MVC. Como você viu na coluna Janeiro, é trabalho o manipulador de rota do encontrar um manipulador HTTP para uma solicitação — isto é um objeto implementar a interface IHttpHandler. Em aplicativos de MVC, esse objeto será um objeto do tipo MvcHandler, e dentro de MvcHandler é onde processamento se torna interessante.

Figura 2 mostra o fluxo de processamento de uma solicitação MVC típica. Quando o controle atinge o MvcHandler, o MvcHandler é capaz de extrair o parâmetro de controlador a RouteData produzido pelo módulo roteamento anteriormente no processamento. O manipulador Finalmente enviará esse parâmetro controlador, que é um valor de seqüência de caracteres, para uma fábrica de controlador. Em seguida, é responsabilidade a fábrica para construir e retornar um controlador. Todos os controladores em um aplicativo MVC implementam a interface IController.

fig02.gif

A Figura 2 fluxo de controle para uma solicitação MVC típica

A estrutura MVC fornece uma padrão controlador fábrica (apropriadamente denominada DefaultControllerFactory) que irá pesquisar em todos os assemblies em um appdomain procurando todos os tipos que implementam IController e cujo nome termina com o controlador. Assim, se você solicitar a fábrica para procurar um controlador de "base", a fábrica pode retornar uma instância recém-instanciada de uma classe HomeController independentemente do namespace ou o assembly que ele reside em — desde que ele implementa IController. Esse comportamento é parte "convenção sobre a configuração" estilo do the MVC. Há mais para o texto de fábrica, mas vamos primeiro terminar com o processamento de MvcHandler.

Uma vez que o MvcHandler possui uma referência IController de fábrica, ele chama o executar no controlador de e aguarda o controlador de trabalho sua mágica. Quando execução for concluída, o MvcHandler verificará se o controlador implementa a interface IDisposable e em caso afirmativo, irá chamar Dispose no controlador para limpar recursos não gerenciados.

Extensibilidade de fábrica

A fábrica de controlador é um ponto extensibilidade principais na estrutura do ASP.NET MVC. Embora a fábrica padrão fornecida pela estrutura pode encontrar um HomeController em qualquer lugar na sua solução, ele só pode instanciar o HomeController se você fornecer um construtor sem parâmetros. Essa limitação é um problema para as equipes que siga o princípio de inversão de dependência e inserir as dependências de um controlador por meio de seu construtor. Como exemplo, considere o EmployeeController (mostrado na Figura 3 ), que requer que alguém passe um componente de log para o construtor somente.

A Figura 3 EmployeeController

public class EmployeeController : IController
{
    public EmployeeController(ILogger logger)
    {
        _logger = logger;
    }

    public void Execute(RequestContext requestContext)
    {
        // ...
    }

    ILogger _logger;
}

Felizmente, você pode criar uma fábrica personalizada. Qualquer classe que implementar a interface IControllerFactory é um candidato e você só precisa implementar métodos CreateController e ReleaseController. No entanto, inversão de controle recipientes como StructureMap, Unity Ninject e Windsor do projeto Castle estão prontamente disponíveis e um perfeito adequado para esse cenário. Na verdade, o Projeto MVC Contrib no CodePlex inclui implementações IControllerFactory para todos os recipientes listados acima.

Se você quiser usar StructureMap como a inversão de controle de recipiente, você pode referenciar os assemblies StructureMap e MvcContrib.StructureMap e escrever o código mostrado na Figura 4 . O método InitializeContainer esta listagem primeiro informa StructureMap usar um tipo de SqlServerLogger sempre que um ILogger for necessária. O código, em seguida, define a fábrica de controlador para o aplicativo inteiro usando o método SetControllerFactory do ControllerBuilder atual. Durante o processamento da solicitação, é será que o MvcHandler pedir esse mesmo ControllerBuilder a fábrica configurada no momento e o trabalhar com um StructureMapControllerFactory em vez da fábrica de estrutura padrão.

A Figura 4 Initialize contêiner

protected void Application_Start()
{
    InitializeContainer();
    RegisterRoutes(RouteTable.Routes);
}

private void InitializeContainer()
{
    StructureMapConfiguration
        .ForRequestedType<ILogger>()
        .TheDefaultIsConcreteType<SqlServerLogger>();

    ControllerBuilder.Current.SetControllerFactory(
        new StructureMapControllerFactory());
}

O StructureMapControllerFactory do projeto MVC Contrib herdar padrão controlador fábrica a estrutura MVC e ainda usará a convenção de que descrevi anteriormente ao localizar tipos de controlador para criar uma instância. No entanto, a fábrica usará StructureMap para instanciar o controlador e StructureMap sabe como trabalhar com construtores com parâmetros. A configuração mostrada na Figura 4 seria tudo que você precisa para processar uma solicitação para http://localhost/Employee/. StructureMap será instanciar o EmployeeController da Figura 3 passando uma referência SqlServerLogger.

fig05.gif

A Figura 5 hierarquia de classe

Execução É apenas o início

Anteriormente eu declarada que o MvcHandler chama o método, espera, o controlador execute e, em seguida, limpa. Isso ocorre porque o MvcHandler conhece apenas controladores por meio de uma interface IController. Se desejar escrever seu aplicativo nesse nível, você pode simplesmente derivar de todos os controladores da interface IController e fornecer uma implementação do método Execute. No entanto, a estrutura MVC ASP.NET oferece um modelo de execução mais sofisticado para controladores por meio a hierarquia de classes mostrada a Figura 5 .

Por padrão, os controladores que você adicionar a um projeto ASP.NET MVC derivam da classe System.Web.mvc.Controller. Uma maneira para adicionar um novo controlador é clique com o botão direito do mouse na pasta controladores no Solution Explorer e selecione Add | controlador, que fornece a caixa de diálogo mostrada na Figura 6 . Lembre-se, para a fábrica de controlador para localizar seu controlador, que o nome deve terminar com controlador.

A classe de base do controlador introduz o conceito de uma ação. Ações são métodos no controlador que servem como o destino de solicitação final em um aplicativo MVC. Anteriormente, eu apontado out que o módulo de roteamento do ASP.NET será levantar check-out "inicial" como o parâmetro controlador a partir de uma URL de http://localhost/home/index/. Isso há informação suficiente para rotear a solicitação para o controlador adequado. O módulo de roteamento também separado fora do índice como um parâmetro de ação. Quando o MvcHandler aciona o HomeController para executar, é a lógica composta dentro da classe base do controlador para inspecionar este parâmetro de ação e chamar o método adequado controlador. A maioria dessa lógica de roteamento de ação reside dentro da classe ControllerActionInvoker pública.

fig06.gif

A Figura 6 adicionar controlador

a Figura 7 é o HomeController fornecida pelo modelo de projeto ASP.NET MVC. O público métodos, o índice da instância e sobre, representam a estrutura chamará quando o cliente solicita casa/índice de ações/e casa/sobre /, respectivamente. Qualquer método de instância pública poderá servir como uma ação de controlador, desde que a estrutura pode determinar para determinados que a ação é a ação correta a chamar (em outras palavras, cuidado com sobrecarga de método). Há regras adicionais em execução à estrutura está procurando por uma ação para invocar. Você pode influenciar a escolha da estrutura de ações, estabelecer regras adicionais para a seleção de ação e manipular o comportamento de suas ações usando atributos.

A Figura 7 HomeController

[HandleError]
public class HomeController : Controller
{
    public ActionResult Index()
    {
        ViewData["Message"] = "Welcome to ASP.NET MVC!";

        return View();
    }

    public ActionResult About()
    {
        return View();
    }
}

Seletor de atributos

Você pode Decore uma ação de controlador com atributos de seletor para fornecer as informações de estrutura adicionais a serem considerados quando ele é selecionar uma ação para invocar. Por exemplo, adicionar um atributo de [NonAction] para um método de controlador fará com que o método a ser excluída da lista de ações disponíveis. Você também pode fornecer um método um nome de ação específica. Por padrão, o nome de um método também é o nome da ação, mas se você colocar [ActionName("help")] em seu HomeController é sobre o método, "sobre" é não uma ação válida para o seu controlador. Em vez disso, nome da ação do método sobre é "Help" e a estrutura será chamar o método de sobre para solicitações, como/local/ajuda /.

Um atributo de seletor importante é o atributo AcceptVerbs. Este atributo permite apenas que a estrutura selecionar uma ação quando um dos verbos listados no atributo coincide com o verbo da solicitação HTTP atual. Por exemplo, decoração with[AcceptVerbs(HttpVerbs.Post) um método] significa que o método só pode ser chamado como uma ação para uma operação HTTP POST. É importante selecionar o verbo adequado para suas ações de controlador, principalmente se as ações modificar o estado no servidor. Para obter mais informações, consulteDica sobre o ASP.NET MVC do Stephen Walther #46.

Atributos de filtro

Filtros de ação são outro tipo de atributo que você pode colocar em uma ação. Você pode adicionar armazenamento em cache, validação e comportamentos para suas ações usando um modelo de programação declarativo de tratamento de erros com filtros de ação. Um exemplo de um atributo de filtro é o atributo [HandleError] o HomeController na Figura 7 . Você pode aplicar esse atributo para ações individuais ou adicione o atributo à classe controlador para aplicar o comportamento a todas as ações em um controlador.

Quando um atributo HandleError está presente em uma ação e a ação lança uma exceção, a estrutura MVC procurará por um modo de exibição com o nome de "erro" — primeiro na pasta do modo de exibição do controlador de e também na pasta de exibição compartilhada. A exibição de erro lhe permite apresentar ao usuário com uma página de erro amigável. Você também pode mapear exceções para modos de exibição específicos usando um atributo HandleError mais explícito. Por exemplo, [HandleError(ExceptionType=typeof(SqlException), modo de exibição = "DatabaseError")] deve mapear uma SqlException unhandled para uma exibição denominada DatabaseError. O restante dos filtros de ação fornecidos pela estrutura MVC são descritos na Figura 8 .

Figura 8 filtros de ação
Nome Descrição
OutputCacheAttribute Semelhante à diretiva OutputCache em formulários da Web do ASP.NET. O atributo de OutputCache permite que a estrutura MVC para armazenar em cache a saída de um controlador.
ValidateInputAttribute Semelhante ao atributo ValidateRequest em um formulário da Web. Por padrão, a estrutura MVC irá inspecionar uma solicitação de HTTP de entrada para HTML ou outra entrada perigosa. Se detectado, uma exceção será gerada. Você pode usar esse atributo para desativar a validação de solicitação.
AuthorizeAttribute O atributo de autorizar permite que você coloque verificações de autorização declarativa em ações de controlador. O atributo pode restringir uma ação para usuários em funções específicas. Você pode usar esse atributo quando você cria uma ação que só deve estar disponível aos usuários na função de administrador.
ValidateAntiForgeryTokenAttribute Esse atributo é uma metade da solução para ajudar a impedir o cross site solicitar forgeries (CSRF). Ele permite que a estrutura de verificar a presença de um token de específicas do usuário no HTTP POSTs. Para obter mais informações sobre CSRFs, consulte"Impedir que entre sites solicitar falsificado (CSFR) usando AntiForgeryToken() auxiliar do ASP.NET MVC."

Filtros de ação personalizada

Você pode criar seus próprios filtros ação para envolver uma ação com lógica personalizada. O código na Figura 9 é o código para um filtro de ação de log simples que pode gravar a saída de janela do Visual Studio durante a depuração. Nós pode aplicar esse atributo para uma ação individual, ou podemos colocar este atributo em uma classe controlador ter log para todas as ações em um controlador.

Figura 9 A ação de log de filtro

public class LogAttribute : ActionFilterAttribute
{
    public override void OnActionExecuting(ActionExecutingContext filterContext)
    {
        Log("Action Executing", filterContext.RouteData);
    }

    public override void OnActionExecuted(ActionExecutedContext filterContext)
    {
        Log("Action Executed", filterContext.RouteData);
    }

    public override void OnResultExecuting(ResultExecutingContext filterContext)
    {
        Log("Result Executing", filterContext.RouteData);
    }

    public override void OnResultExecuted(ResultExecutedContext filterContext)
    {
        Log("Result Executed", filterContext.RouteData);            
    }

    void Log(string stageName, RouteData routeData)
    {
        Debug.WriteLine(
            String.Format("{0}::{1} - {2}", 
                routeData.Values["controller"],
                routeData.Values["action"],
                stageName));
    }        
}

Como você pode ver, há quatro métodos virtuais fornecidos pela classe base ActionFilter. Você pode substituir um ou mais desses métodos, não apenas ações de pré e post-process controlador, mas também pré e post-process o controlador de resultado da ação. Antes de executa uma ação, o método OnActionExecuting será acionado e quando a ação é concluída o método OnActionExecuted será acionado (e acionará mesmo se a ação jogar uma exceção não tratada). Da mesma forma, o método OnResultExecuting será disparado antes do resultado é executado e o método OnResultExecuted será disparado depois.

O parâmetro de contexto passado para os métodos de filtro ação permitirá que você inspecionar a solicitação HTTP, o contexto HTTP, os dados de roteiro e mais. Gerar uma exceção de um desses métodos será interrompido a solicitação de processamento de fluxo. Uma exceção é uma ferramenta útil se você estiver escrevendo um ActionFilter para verificar preconditions no ambiente.

Obtendo resultados

A execução bem-sucedida de uma ação de controlador MVC produzirá um objeto derivado de ActionResult. Processamento de um modo de exibição e redirecionar o navegador para uma nova URL são ambos os tipos válidos de resultados que pode desejados do seu controlador de. A lista completa dos tipos de ActionResult derivado é mostrada na Figura 10 .

Tipos derivados de Figura 10 ActionResult
Nome Comportamento de estrutura Método de produção
ContentResult Grava um valor de seqüência de caracteres diretamente na resposta HTTP. Conteúdo
EmptyResult Não grava à resposta HTTP.  
FileContentResult Leva o conteúdo de um arquivo (representado como uma matriz de bytes) e gravar o conteúdo na resposta HTTP. Arquivo
FilePathResult Toma o conteúdo de um arquivo no local fornecido e grava o conteúdo na resposta HTTP. Arquivo
FileStreamResult Toma um fluxo de arquivo produzido pelo controlador e grava o fluxo na resposta HTTP. Arquivo
HttpUnauthorizedResult Um resultado especial usado pelos filtros de autorização quando falhas de verificações de autorização.  
JavaScriptResult Responde ao cliente com um script para o cliente executar. JavaScript
JsonResult Responde ao cliente com dados em JSON (JavaScript Object Notation). JSON
RedirectResult Redireciona o cliente para uma nova URL. Redirecionar
RedirectToRouteResult Processa a exibição especificada para responder com um fragmento de HTML (geralmente usado em cenários de AJAX). RedirectToRoute/RedirectToAction
PartialViewResult Processa a exibição especificada para responder com um fragmento de HTML (geralmente usado em cenários de AJAX). PartialView
ViewResult Processa o modo de exibição especificado e responde ao cliente com HTML. Modo de exibição

Observe que uma ação de controlador nunca precisa instanciar um desses tipos diretamente. Em vez disso, a ação de controlador pode chamar o nome do método mostrado na Figura 10 para produzir o resultado. Esses métodos são herdados da classe base do controlador de MVC. Também vale a pena observar que uma ação de controlador não precisa retornar um objeto ActionResult. Se o controlador retorna algo diferente de um ActionResult, a estrutura irá converter o objeto em uma seqüência de caracteres e encapsular a seqüência de caracteres em um ContentResult (que simplesmente grava a seqüência de caracteres na resposta HTTP). Um controlador que retorna void produzirá um EmptyResult.

A classe ActionResult define um método ExecuteResult que cada um dos tipos na Figura 10 substituirá. Esse método é chamado pelo ControllerActionInvoker — o mesmo objeto chamado ação do controlador de. Quando invocada, cada resultado irá se encarregar de todos os detalhes pequenos necessários para ministrar com êxito o resultado para o cliente. Por exemplo, o resultado de JavaScript será definido o cabeçalho de tipo de conteúdo da resposta para "Application/x-JavaScript", enquanto o HttpUnauthorizedResult definirá o código de status HTTP da resposta a uma 401 (não autorizado).

Uma resposta comum de uma ação de controlador será um ViewResult. Você já viu esse resultado nas listagens de código anterior como todas as suas ações tiverem chamado o método de modo de exibição do controlador e retornou o resultado. Este é outro exemplo de "convenção sobre configuração," porque o ViewResult, quando usado dessa maneira padrão, procurará por um modo de exibição na pasta do modo de exibição do controlador e com um nome de arquivo correspondente a ação. Por exemplo, views\home\about.aspx é o modo de exibição convencional para a ação sobre do controlador de início. As versões sobrecarregadas do método de modo de exibição permitem que você declarar explicitamente o nome da exibição.

A ação está em

Neste mês eu visualizá-la profundidade no comportamento ao redor ASP.NET MVC controladores e abstrações. Yo u agora deve ter um bom entendimento de como a estrutura MVC encontra, cria e usa controladores, bem como ligar para os pontos de extensibilidade do framework MVC giram em torno de controladores. Na próxima edição desta coluna, vai vejamos diretrizes e práticas recomendadas para colocar esses controladores para trabalhar em aplicativos reais.

Idéias: métodos de auxiliar

Se você sentiu estranho usando os métodos de auxiliar para resultados de ação quando eles apareciam pela primeira vez na estrutura (View(), Content()), você deve estar se perguntando como tudo veio sobre e qual era por trás dessa decisão de design específico.

Bem, a história por trás os métodos auxiliares para retornando resultados de ação é que 99 % de tempo de um desenvolvedor de MVC escrevendo um aplicativo MVC vai ser gasto escrever ações do controlador. Nós queríamos Verifique se o método comum é limpa legível e como declarativa possível.

Por exemplo, você ainda pode escrever um método de ação assim:

public ActionResult Foo {
    // ... do stuff ...
    ViewData.Model = myModel;
    return new ViewResult {ViewName = "Foo", ViewData = this.ViewData};
}

Queríamos limpar isso um pouco, portanto, fizemos alguns ajustes, como você pode ver:

public ActionResult Foo {
    // ... do stuff ...
    return new View(myModel);
}

Essa é uma abordagem mais declarativa (Apesar do uso de uma linguagem muito imperativa). Quando você lê esse método de ação, ele reflete sua intenção. " Eu quero retornar uma exibição que contém esse modelo."

Gerente de programa--Phil Haak, sênior, Microsoft

Envie suas dúvidas e comentários para xtrmasp@microsoft.com.

k. Scott Allen é um membro da equipe técnica Pluralsight e fundador da OdeToCode. Você pode acessar Scott em Scott@OdeToCode.com ou ler seu blog em odetocode.com/blogs/Scott.