Postado na(s) categoria(s) ASP.Net MVC pelo Giovanni Bassi em 26 de julho de 2008 às 20:50 | Tags: , , ,

Ninguém avaliou. Dê sua nota!

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

 

chaveautautmvc Dei uma boa olhada na nova funcionalidade de autenticação e autorização para o ASP.Net MVC, e posso dizer que ficou bem legal. Gostei do que vi, ficou simples e fácil de aplicar. Assim como todas essas novas funcionalidades, esta está vindo também através de um Interception Filter. Basicamente o que o filtro faz é verificar se você está autenticado, e opcionalmente, autorizado a acessar uma determinada ação ou controller.

O atributo é o AuthorizeAttribute, e você pode ver o que ele está fazendo no repositório do fonte no Codeplex. Note que, basicamente, ele está verificando se o usuário está autenticado, olhando para a user.Identity.IsAuthenticated:

IPrincipal user = filterContext.HttpContext.User;
if (!user.Identity.IsAuthenticated) {
filterContext.Cancel = true;
filterContext.Result = new HttpUnauthorizedResult();
return;

 

Nada de mais, certo? Para autorizar é mais ou menos a mesma coisa, ele pega a lista de usuários ou papéis (roles) e verifica:

if (!String.IsNullOrEmpty(Users)) {
IEnumerable<string> validNames = SplitString(Users);
bool wasMatch = validNames.Any(name => String.Equals(name, user.Identity.Name, StringComparison.OrdinalIgnoreCase));
if (!wasMatch) {
filterContext.Cancel = true;
filterContext.Result = new HttpUnauthorizedResult();
return;
}
}
if (!String.IsNullOrEmpty(Roles)) {
IEnumerable<string> validRoles = SplitString(Roles);
bool wasMatch = validRoles.Any(role => user.IsInRole(role));
if (!wasMatch) {
filterContext.Cancel = true;
filterContext.Result = new HttpUnauthorizedResult();
}
}

Além deste atributo, que faz o trabalho pesado de autenticação e autorização, há um controller para auxiliar no contato com o aplicativo em si. Ele se chama AccountController, e já vem no projeto. Há também algumas views que esse controle utiliza. Dêem uma olhada no Solution Explorer, com os itens novos destacados:

solexplautenautormvc

Já o controller em si traz os seguintes métodos:

class view - account controller

Como podemos ver, ele tem ações para trocar senha, logar, deslogar, e criar um novo usuário (register). Ele não lista usuários, cria grupos e outras tarefas administrativas. Pelo que eu li nos blogs da Microsoft, eles esperam que tarefas administrativas sejam feitas de outra forma, e sugerem que no IIS 7 isso já é mais fácil. Isso pode querer dizer que não vai rolar um sistema de gestão de usuários no MVC. Para compensar isso há a boa notícia de que eles vão evoluir um pouco mais esse controlador e as views, permitindo trocar os mecanismos de autenticação e autorização, se não quisermos usar o membership do ASP.Net, que é onde o atributo [Authorize] e o controlador estão acoplados atualmente. Será possível estender este modelo de 2 formas então:

  1. Trocando o membership do ASP.Net por algum outro framework;
  2. Trocando o provider de membership do ASP.Net. Para permitir isso, o construtor do controlador já inicia com uma injeção de dependência bonita, dêem uma olhada:

   16 public AccountController()

   17     : this(null, null)

   18 {

   19 }

   20 

   21 public AccountController(IFormsAuthentication formsAuth, MembershipProvider provider)

   22 {

   23     FormsAuth = formsAuth ?? new FormsAuthenticationWrapper();

   24     Provider = provider ?? Membership.Provider;

   25 }

Essa interface, IFormsAuthentication, é nova, e é parte do MVC. O MembershipProvider é o velho conhecido MembershipProvider do ASP.Net. Dessa forma, fica fácil injetar um outro provider, para testar, e até mesmo trocá-lo. Para arrancar de vez o Membership do ASP.Net (primeira opção acima), a recomendação até agora é refazer o controlador. Mas isso vai melhorar.

Vimos que há view para trocar senha, para fazer login e se cadastrar. Como fica? Vou mostrar um screenshots abaixo, mas antes fiz um controlador simples, onde um usuário normal só pode ver uma lista de categorias, e o usuário admin pode alterar. Vejam o controlador:

    1 public class CategoriaController : Controller

    2 {

    3     [Authorize(Roles="All,Admin")]

    4     public ActionResult Index()

    5     {

    6         return View("Index", (new Northwind2005Model.NorthwindEntities()).

    7             Categories.ToList());

    8     }

    9 

   10     [Authorize(Roles = "Admin")]

   11     public ActionResult Edit(int id)

   12     {

   13         var northwind = new Northwind2005Model.NorthwindEntities();

   14         var categoria = (from cat in northwind.Categories

   15                         where cat.CategoryID == id

   16                         select cat).First();

   17         return View(categoria);

   18     }

   19 

   20     [Authorize(Roles = "Admin")]

   21     public ActionResult Update(int id)

   22     {

   23         var northwind = new Northwind2005Model.NorthwindEntities();

   24         var categoria = (from cat in northwind.Categories

   25                         where cat.CategoryID == id

   26                         select cat).First();

   27         BindingHelperExtensions.UpdateFrom(categoria, Request.Form);

   28         northwind.SaveChanges();

   29 

   30         return Index();

   31     }

   32 }

Naturalmente a ação index, que é a padrão, lista os usuários, mas antes eu preciso estar autenticado. Então, quando eu clico na aba de categorias, sou direcionado à view de login pelo controlador:

Formulário de login do ASP.Net MVC

Após autenticar, por algum motivo, ele me redireciona de volta à Home (porque será?). Tenho que clicar novamente na aba de categorias que criei para finalmente ver as categorias, exibida pela ação index (notem o login aparecendo em destaque):

Exibição das categorias, com destaque no usuário autenticado (usuário comum)

Mas eu loguei com um usuário comum. Ao tentar editar, sou direcionado ao login de novo, como se fosse para logar como admin. Logo como admin, ele volta à Home de novo (!?), navego até as categorias e tento editar. Agora já consigo editar e salvar. Essa é ação Edit, note mais uma vez o login no canto superior direito. Agora é o usuário admin:

Edição das categorias, com destaque no usuário autenticado (usuário admin)

Não gostei dessa história. Porque não posso ser direcionado de volta à mesma página, para exibir uma mensagem? Busquei uma forma simples. Ainda não há.

É possível ainda incluir um novo usuário via link de Register, ação também chamada Register (pode ser visto na primeira imagem do IE acima):

Formulário de criação de contas do MVC

E trocar de senha:

Formulário de troca de senha do MVC

Uma das coisas que achei mais interessantes está na ação de login: ela posta para si mesma, e dessa forma controla exibição de erros, como senha muito curta. Muito inteligente.

Conclusão dessa verificação do código de autorização e autenticação: com esse exemplo já dá para confirmar que o negócio funciona direitinho, mas precisa ainda evoluir um pouco em usabilidade e extensibilidade. Vamos aguardar agora o Preview 5, que deve sair daqui uns 2 meses.


Postado na(s) categoria(s) ASP.Net MVC pelo Giovanni Bassi em 26 de julho de 2008 às 20:47 | Tags:

Ninguém avaliou. Dê sua nota!

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Mais uma olhada no recém lançado Preview 4 do ASP.Net MVC. Se você chegou aqui agora, vale a pena dar uma olhada nos outros posts. Nesse vou dar uma olhada no tratamento de erros, que é feito com um Filter Interceptor. Eu já havia visto o cache com Filter Interceptor, e a implementação do tratamento de erro é também muito simples, seguindo o mesmo modelo de atributos em funções. É mais simples, inclusive, do que era antes com Web Forms. E é bem configurável.

Fiz 2 ações no controlador “Quebrado”: ação Index, que é a padrão (não precisa especificar), não trata o erro, e ação “tratada”, que trata o erro.

Antes, quando você tinha um erro, você recebia a seguinte tela de erro, se tivesse os custom errors desligados (ação Index):

Erro Padrão do ASP.Net com ASP.Net MVC- CustomErrors Off

Se custom errors estiver ligado, a mensagem é a seguinte (ação Index):

Erro Padrão do ASP.Net com ASP.Net MVC- CustomErrors On

Até aí, essa é a resposta padrão do ASP.Net, todos conhecemos a velha tela amarelona (e não gostamos de vê-la, não é verdade?). O ASP.Net MVC traz agora uma novidade: pode-se tratar erros com um simples Interceptor Filter, que é aplicado com um atributo no método (ação do MVC) ou na classe (controlador).

Se a exibição dos erros erros estiver habilitada (custom errors off), e uma ação tiver um erro, a view de erros será exibida, conforme a figura abaixo (note que essa é a ação “tratada”):

Nova View de erros - CustomErrors Off

E se estiver desabilitada (custom errors on), será exibida uma mensagem mais simples, sem o detalhamento do problema (o que é prática comum de segurança) – exibindo ação “tratada”:

Nova View de erros - CustomErrors On

Já se você quiser fazer um tratamento customizado do erro, você pode. Abaixo fiz uma view padrão para mostrar erros de overflow (mais uma vez, ação “tratada”:

View de erros Customizada

Como funciona? Muito simples. Vejam abaixo o código do controller:

    9 public class QuebradoController : Controller

   10 {

   11     public ActionResult Index()

   12     {

   13         return JogaErro();      

   14     }

   15 

   16     [HandleError(ExceptionType = typeof(OverflowException), View = "OverflowException")]

   17     [HandleError()]

   18     public ActionResult Tratada()

   19     {

   20         return JogaErro();

   21     }

   22 

   23 

   24     public ActionResult JogaErro()

   25     {

   26         if (Session["aleatorio"] == null)

   27             Session["aleatorio"] = 0;

   28         var aleatorio = (int)Session["aleatorio"];

   29         aleatorio++;

   30         if (aleatorio > 1)

   31             aleatorio = 0;

   32         Session["aleatorio"] = aleatorio;

   33 

   34         switch (aleatorio)

   35         {

   36             case 0:

   37                 throw new OverflowException("Essa é uma OverflowException.");

   38             default:

   39                 throw new ApplicationException("Essa é uma ApplicationException.");

   40         }

   41     }   

   42 }

A acão “tratada” tem 2 atributos chamados HandleError, que são os atributos que fazem o tratamento. O primeiro informa que trata exceções de overflow, e especifica a View, através de parâmetros, ficando a View de nome “OverflowException” responsável por esses erros. O segundo trata todas as outras exceções, e utiliza a View padrão, que é chamada Errors.aspx, e fica no diretório /Views/Shared. Vejam o Solution Explorer:

Solution explorer

Vejam o código da View:

    7 namespace MvcApplicationErrorHandler1.Views.Shared

    8 {

    9     public partial class Error : ViewPage<HandleErrorInfo>

   10     {

   11     }

   12 }

Ela utiliza como modelo um objeto HandleErrorInfo, que é o seguinte:

    1 namespace System.Web.Mvc

    2 {

    3     public class HandleErrorInfo

    4     {

    5         public HandleErrorInfo(Exception exception, string controller, string action);

    6 

    7         public string Action { get; }

    8         public string Controller { get; }

    9         public Exception Exception { get; }

   10     }

   11 }

Esse objeto tem propriedades para a ação, para o controlador, e para a exceção lançada. Minha customizada utiliza esses dados:

    1 <%@ Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master"

    2 AutoEventWireup="true" CodeBehind="OverflowException.aspx.cs"

    3 Inherits="MvcApplicationErrorHandler1.Views.Quebrado.OverflowException" %>

    4 <asp:Content ID="Content1" ContentPlaceHolderID="MainContent" runat="server">

    5     <h2>Você teve uma OverflowException</h2>

    6     <b>Dados:</b><br />

    7     <b>Action:</b>              <% =this.ViewData.Model.Action %><br />

    8     <b>Controller:</b>          <% =this.ViewData.Model.Controller %><br />

    9     <b>Mensagem da exceção:</b> <% =this.ViewData.Model.Exception.Message %><br />

   10 </asp:Content>

E o resultado é a imagem lá em cima.

Achei o resultado muito bom. Dá para tratar erros muito bem. Diferente do AJAX com MVC, já é uma função bem completa. Já imagino uma classe que herde de ViewPage Controller tipo uma ErrorHandlerViewPage ControlleBase, sendo colocada como classe de base, e podendo até já realizar o tratamento de erro. Para o log do erro, imagino que seria com a criação de outro filter interceptor. Vou pensar nisso depois coloco aqui. Alguma sugestão pessoal?


Postado na(s) categoria(s) ASP.Net MVC pelo giovanni bassi em 23 de julho de 2008 às 21:00 | Tags: , ,

Ninguém avaliou. Dê sua nota!

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Continuo testando o recém lançado Preview 4 do ASP.Net MVC. Essa versão veio com uma implementação inicial com AJAX, conforme explica a documentação:

“We continue to work on enhancing the AJAX features for ASP.NET MVC. The features described here are preliminary versions of features that we expect to enhance in future releases.”

ou...

“Continuamos a trabalhar para melhorar as funcionalidades de AJAX para o ASP.Net MVC. As funcionalidades descritas aqui são versões preliminares das funcionalidades as quais esperamos melhorar em versões futuras.”

Ainda bem que eles adiantaram o assunto, porque realmente as funcionalidades são muito iniciais mesmo. Boa parte do trabalho vem baseado na library de AJAX da Microsoft, que vem encapsulado no já bem conhecido arquivo MicrosoftAjax.js. Enquanto este arquivo tem mais de 6000 linhas de código, o do MVC ainda não passou de 200. Imagino que eles estejam tratando essa versão como um direcionador para as versões futuras. Quando falei que ia demorar um pouco até sair a versão final do ASP.Net MVC, já imaginava esse tipo de coisa.

Na verdade, até prefiro assim. Prefiro uma versão mais completa que demora um pouco mais a uma versão mais ou menos lançada antes.
Até porque, quando você lança antes mas sem boa parte das funcionalidades que queria que estivesse na v1, acaba por ouvir reclamações de todos os lados, são feitas comparações com outros produtos semelhantes, dizendo-se que são melhores, e por aí vai. No caso da Microsoft, ela tem o seu excelente histórico de Web Forms a bater, o que não é fácil, depois de tudo que já conseguimos fazer com altíssima produtividade. No caso do AJAX é a mesma coisa. Agora que o AJAX heaven paira sobre nós quem vai querer abandoná-lo? Pois é. Tudo isso me criou uma expectativa com esse release do CTP 4, não posso mentir.

Enfim, vamos ao que vi. Existe agora uma propriedade chamada AJAX na ViewPage, que devolve um objeto do tipo AjaxHelper. Esse é o objeto responsável por fazer o trabalho de contato com Ajax. Nesse momento, ele possui apenas ActionLinks, para criar links que trabalham com Ajax, como se fossem LinkButtons, e uma função para criar um formulário html Ajax. É isso. E o que esses métodos fazem básicamente é criar ligações com o Javascript do arquivo MicrosoftAjax.js, e o novo MicrosoftMvcAjax.debug.js, a library de Javascript do ASP.Net MVC.

Você deve adicionar manualmente a referência aos arquivos Javascript do Ajax. O ideal é fazer na Master Page para não ter que fazer de novo. Para testar, é só criar um controlador simples. Fiz um com a ação Index padrão que só chama a View a ser Renderizada. Fiz também duas funções do Ajax, que já explico. Dêem uma olhada como ficou:

public class AjaxTestController : Controller
{
    public ActionResult Index()
    {
        return View();
    }

    public string ObterHorario()
    {
        var drpLista = Request.Form["drpLista"];
        string ret = "Item selecionado: " + drpLista + "
          Hora: " + DateTime.Now.ToString("dd/MM/yyyy hh:mm:ss");
        return ret;
    }

    public string ObterHorarioSegundo()
    {
        var drpLista = Request.Form["drpLista"];
        string ret = "Item selecionado: " + drpLista + "
          Segundo atual: " + DateTime.Now.ToString("ss");
        return ret;
    }    
}

As funções que trabalharão com Ajax são as duas que retornam strings: ObterHorario e ObterHorarioSegundo. Notem que essas ações não retornam ActionResults, como é o padrão em uma ação. Elas são chamadas no código, e o que é feito é uma substituição do valor de um elemento html com o valor retornado. As duas funções utilizam o valor de um DropDownList que está na View (veja abaixo), e concatenam com valores da hora atual.

Vejam como ficou a aspx:

<%@ Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master" 
AutoEventWireup="true" CodeBehind="Index.aspx.cs" 
Inherits="MvcApplicationAjax1.Views.AjaxTest.Index" %>
<asp:Content ID="Content1" ContentPlaceHolderID="MainContent" runat="server">
<% using(Ajax.Form("ObterHorario",
       new AjaxOptions() { UpdateTargetId="lblOut"}) )
    { %>
    <% =Html.DropDownList("drpLista",
                new SelectList(new[] { 
                new { id = 1, desc = "um" }, 
                new { id = 2, desc = "dois" } ,
                new { id = 3, desc = "três" }
            }, "id", "desc"))%> <br />
    <% =Html.SubmitButton("submit","Recupere a hora 2") %><br />
    
    <% =Ajax.ActionLink("Recupere o segundo atual",
        "ObterHorarioSegundo", 
            new AjaxOptions() { UpdateTargetId="lblOut"}) %>
    <br />
    
    <span id="lblOut"></span>
    
<% } %>
</asp:Content>

Nada de mais, criei:

  • Um form Ajax, que aponta para atualizar o span chamado “lblout” e para a função do controlador ObterHorario.
  • O DropDownList preenchido com uma lista de valores (vai gerar uns selects e uns options).
  • Um botão submit simples.
  • Um link que vai chamar a função ObterHorarioSegundo.
  • Um span para receber o valor.

Funciona direitinho. Ao clicar no botão ou no link o texto respectivo é exibido, através da substituição do conteúdo do span. Vejam como ficou a view (clique para ampliar):

Exibindo após clicar o botão com Ajax

Note a observação abaixo “Item selecionado: 1”, e a hora na linha debaixo. Isso quer dizer que funcionou.

Abaixo temos o resultado ao clicar no Link (clique para ampliar):

Exibindo após clicar o link com Ajax

Já não é possível ver o valor do DropDownList. Isso é até esperado, já que o link não deve ter submetido o form.

Outra coisa meio estranha é que, se você deixar o span assim: <span id="lblout" />, em vez de usar uma tag de abertura e outra para fechar, ele dá problema, e some com o link e com o botão… vai entender.

Achei interessante essa primeira implementação. É um CTP (Preview), é verdade, mas esperava um pouquinho mais. Provavelmente o time estava mais envolvido com a parte de autenticação e autorização, que vou analisar postar em seguida.

E vocês, o que estão achando?


Postado na(s) categoria(s) ASP.Net MVC pelo giovanni bassi em 21 de julho de 2008 às 21:07 | Tags: ,

Ninguém avaliou. Dê sua nota!

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Acabo de testar o novo OutputCache do ASP.Net MVC Preview 4. Notei que ele não tem uma forma de configurar uma dependência de Cache com SQL, nem mesmo via perfil de cache (Cache profile). De resto, funciona perfeitamente.

Para confirmar criei um projeto de testes e analisei um pouco mais a fundo. Dêem uma olhada como ficou meu Web.config abaixo.

Primeiro a seção de strings de conexão:

  <connectionStrings>
    <add name="Northwind2005ConnectionString" 
    connectionString="data source=gb2;Initial Catalog=Northwind2005;User ID=user;password=pwd" providerName="System.Data.SqlClient"/>
  </connectionStrings>

E agora seção de cache:

     <caching>
      <sqlCacheDependency enabled="true">
        <databases>
          <add name="Northwind2005" 
          connectionStringName="Northwind2005ConnectionString" 
          pollTime="10000"/>
        </databases>
      </sqlCacheDependency>
      <outputCacheSettings>
        <outputCacheProfiles>
          <add name="NorthwindCacheProfile" varyByParam="none" 
          sqlDependency="Northwind2005:Employees" 
          enabled="true" duration="600"/>
        </outputCacheProfiles>
      </outputCacheSettings>
    </caching>

Tudo configurado corretamente. Se você aplicar esse xml no seu web.config para trabalhar com web forms e aplicar um diretiva de @OutputCache na página vai funcionar.

No ASP.Net MVC funciona assim: você cria uma ação, e coloca o atributo de OutputCache. Para testar, criei um controlador de cache, e duas ações, a padrão, Index, e outra, para testar a interação com a dependência SQL, que usa a mesma View. Vejam como ficou:

namespace MvcApplication1.Controllers
{
    public class CacheTestController : Controller
    {
        [OutputCache(Duration=10)]
        public ActionResult Index()
        {
            ViewData["mensagem"] = "Última atualização às " 
            + DateTime.Now.ToString("dd/MM/yyyy hh:mm:ss");
            return View();
        }

        [OutputCache(CacheProfile = "NorthwindCacheProfile")]
        public ActionResult SQLCacheDep()
        {
            ViewData["mensagem"] = "(SQL Dep) Última atualização às " 
            + DateTime.Now.ToString("dd/MM/yyyy hh:mm:ss");
            return View("Index");
        }
    }
}

A primeira funciona ok. A segunda resulta em um cache que só expira quando a duração é alcançada, ou seja, em 10 minutos (600 segundos). Abri um SQL Profiler e constatei: nada acontecendo lá, nenhuma conexão vindo da aplicação. Se fosse Web Forms estaria rodando a procedure “AspNet_SqlCachePollingStoredProcedure” para ver se alguma coisa mudou.

Para terminar, confirmei no código fonte do ASP.Net MVC a classe OutputCacheAttribute. Ela tem uma função chamada ApplyProfile, onde ela aplica os dados do Cache Profile, vejam só:

public void ApplyProfile(OutputCacheProfile profile) {
    Duration = profile.Duration;
    Location = profile.Location;
    NoStore = profile.NoStore;
    VaryByContentEncoding = profile.VaryByContentEncoding;
    VaryByCustom = profile.VaryByCustom;
    VaryByHeader = profile.VaryByHeader;
    VaryByParam = profile.VaryByParam;
}

Percebem como ela não aplica a propriedade “SqlDependency” do profile? Taí a explicação. O profile está sendo aplicado só com a duração configurada para expirar (propriedade duration), mais nada.

Imagino que a implementação deve sair no Preview 5, vamos ver.


Postado na(s) categoria(s) ASP.Net MVC pelo giovanni bassi em 20 de julho de 2008 às 14:24 | Tags:

Ninguém avaliou. Dê sua nota!

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Estou dando uma olhada no ASP.Net MVC Preview 4, e estou agora entrando em contato com uma feature que existe desde o Preview 2: os ActionFilters.

Com eles você pode colocar ações que acontecem antes das ações de um controlador, e antes da execução do ActionResult retornado pela ação. Você pode pegar erros, criar cache, e até cancelar uma ação (entre várias outras coisas).

Observação: Se você não sabe o que são ActionResults, por enquanto pense assim: são ações encapsuladas (seguem o Design Pattern Command – mais informações aqui e aqui). Quando alguém chama uma ação de um controlador, ele retorna um ActionResult para ser executado. O ActionResult mais comum é o ViewResult, que retorna uma ação de renderizar uma View, ou mais claramente, uma página. Podem existir outros tipos de ActionResult, para baixar arquivos, por exemplo.

Pois bem, criei um logger, bem simples, só para exibir o que está se passando, e criei uma View para exibí-lo. Vejam como foi.

Criei um projeto com Preview 4, e criei um ActionFilterAttribute (uma classe que herde de ActionFilterAttribute). Esse ActionFilterAttribute permite que você crie os tais dos filtros de ação. No meu caso o filtro chamou-se GiggioLogAttribute:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;

namespace MvcApplication1.ActionFilters
{
    public class GiggioLogAttribute : ActionFilterAttribute
    {
        public override void OnActionExecuted(ActionExecutedContext filterContext)
        {
            base.OnActionExecuted(filterContext);
            filterContext.Log("OnActionExecuted");
        }
        public override void OnActionExecuting(ActionExecutingContext filterContext)
        {
            base.OnActionExecuting(filterContext);
            filterContext.Log("OnActionExecuting");
        }
        public override void OnResultExecuted(ResultExecutedContext filterContext)
        {
            base.OnResultExecuted(filterContext);
            filterContext.Log("OnResultExecuted");
        }
        public override void OnResultExecuting(ResultExecutingContext filterContext)
        {
            base.OnResultExecuting(filterContext);
            filterContext.Log("OnResultExecuting");
        }
    }
    static class LoggerHelper
    {
        public static void Log(this ControllerContext filterContext, string where)
        {
            string routeDataValues = string.Empty;
            foreach (var item in filterContext.RouteData.Values)
            {
                routeDataValues += "\r\n" + item.Key + ": " + item.Value.ToString();
            }
            
            Models.ActionFilterEventLogger.GetLogs().Add(new Models.ActionFilterEventLog()
            {
                ControllerName = filterContext.Controller.ToString(),
                EventName = where,
                RouteDataValues = filterContext.RouteData.Values
            });
        }
    }
}

Notem como estou sobrescrevendo as 4 ações, de antes da ação do controlador (OnActionExecuting), depois (OnActionExecuted), e de antes da execução do resultado da View (OnResultExecuting) e depois (OnResultingExecuted). Pego o contexto de filtro e passo para um método de extensão chamado Log, onde criou um objeto ActionFilterEventLog e adiciono à uma coleção de logs que fica guardada em uma variável de aplicação escondida atrás da função ActionFilterEventLogger.GetLogs(). Com isso, tenho uma coleção em memória do que aconteceu. Para aplicar é fácil. Vejam como ficou com o atributo decorando a ação About do controller Home:

        [ActionFilters.GiggioLog()]
        public ActionResult About()
        {
            ViewData["Title"] = "About Page";

            return View();
        }

Ao chamar o about, nada muda, mas as ações do meu logger são executadas.

Já para exibir, criei uma view, e usei a mesma coleção como modelo. Vejam o controlador, chamado Logger.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;

namespace MvcApplication1.Controllers
{
    public class LoggerController : Controller
    {
        public ActionResult Index()
        {
            return View(Models.ActionFilterEventLogger.GetLogs());
        }
    }
}

Super simples, certo? Simplesmente pega a coleção de logs e repassa à View. No caso, a View não foi nomeada, então segue o mesmo nome da ação: Index.

Vejam a View agora. Primeiro o code behind, onde seto o tipo de modelo:

public partial class Index : ViewPage <List<Models.ActionFilterEventLog>>
{
}

E abaixo a aspx para exibir os dados. Basicamente o que eu estou fazendo é montando uma tabelinha com os dados salvos pelo logger, iterando pela coleção.

<%@ Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master" AutoEventWireup="true" CodeBehind="Index.aspx.cs" Inherits="MvcApplication1.Views.Logger.Index" %>
<%@ Import Namespace="MvcApplication1.Models" %>
<asp:Content ID="Content1" ContentPlaceHolderID="MainContent" runat="server">
    <h2>Logs:</h2>
    <table>        
        <tr>            
            <td><strong>Event Name</strong></td>
            <td><strong>Controller Name</strong></td>
            <td><strong>Route Data</strong></td>
        </tr>
        <% foreach (ActionFilterEventLog log in this.ViewData.Model) %>
        <% { %>
        <tr>
            <td><% =log.EventName %></td>
            <td><% =log.ControllerName %></td>
            <td>
                <% foreach (var item in log.RouteDataValues) %>
                <%{ %>
                    <strong><% =item.Key %>:</strong>&nbsp;<% =item.Value.ToString() %>
                <%} %>
            </td>
        </tr>
        <% } %>
    </table>    
</asp:Content>

Ficou assim:

Logger

Eu gostei bastante da tecnologia. Fácil de usar, rapidíssimo para implementar. Entre a leitura e o projeto final não passei de 40 minutos. Excelente! Em que outras opções vocês acham que esse tipo de técnica ficaria legal?

Quem quiser baixar o código fonte, pegue aqui. Vai rodar em qualquer máquina com ASP.Net 3.5 instalado. As dlls do MVC já vem juntas, então você deve conseguir rodar no Visual Studio 2008 sem o Preview 4 instalado.


Postado na(s) categoria(s) ASP.Net MVC pelo giovanni bassi em 19 de julho de 2008 às 18:10 | Tags:

Ninguém avaliou. Dê sua nota!

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Está disponível no Codeplex desde ontem, 16/7, o quarto preview do ASP.Net MVC. Com novidades de todos os tipos, como novos filter interceptors, output cache, endereçamento de erro, autorização, AJAX e mais um monte de novidades.

Como os caras da Microsoft não dormem, já tem comentário de boa parte do time que o está desenvolvendo, começando pelo ótimo Scott Guthrie (que escreveu ainda antes do lançamento), Scott Hanselman (esse não dorme mesmo), Phil Haack, e Rob Conery. O mais completo é o do ScottGu.

Eu ainda não pus a mão mas vou fazê-lo esta semana, mal posso esperar. Estava contando os dias para este lançamento. São as primeiras demonstrações sérias de amadurecimento do framework.

Já baixou o seu?


Postado na(s) categoria(s) ASP.Net MVC pelo Giovanni Bassi em 17 de julho de 2008 às 19:39 | Tags: , ,

Ninguém avaliou. Dê sua nota!

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5
404 error

Se você leu meus artigos sobre Routing com web forms, ou simplesmente está testando o Routing ou ASP.Net MVC, e resolveu fazer o deploy para o IIS, descobriu que lá a história é outra quando recebe um belo erro 404.

Pois bem, é isso mesmo. O IIS 6 não sabe o que fazer com um request http://localhost/app/controlador/acao/id. Ele vai procurar o diretório, e não vai encontrar. Resultado: erro 404.

Algumas opções:

  1. Mapear todos os requests para o filtro ISAPI do ASP.Net. Vai funcionar, mas aí até mesmo imagens e arquivos javascript, html e css vão ser servidos pelo ASP.Net, o que causa um overhead razoável.
  2. Utilizar rotas que possuem extensão, como http://localhost/app/controlador.ASPX/acao/id, ou http://localhost/app/controlador.MVC/acao/id. No segundo caso, você também vai ter que mapear .MVC para a extensão ISAPI do .Net.
  3. Reescrever a URL. Isso é um hack mesmo, e apesar de funcionar, acho que é demais para um problema tão simples. Você acaba reescrevendo para o IIS requests sem extensão por um filtro ISAPI de terceiros, e depois desfaz a rescrita no ASP.Net. De qualquer forma, se você precisar ir a produção, talvez seja a melhor opção.

Mais informações sobre como fazer essas configurações no blog do Steve Sanderson.

Como as opções são como usar Routing com IIS 6, não coloquei acima a melhor de todas: Migrar para Windows Server 2008 e IIS 7. É mais rápido, mais escalável, mais fácil de administrar, mais plugável, mais extensível, etc, etc, etc. Se você é desenvolvedor, o Windows Vista já vem com o IIS 7.


Postado na(s) categoria(s) ASP.Net MVC , ASP.Net Routing pelo Giovanni Bassi em 14 de julho de 2008 às 00:42 | Tags: ,

Ninguém avaliou. Dê sua nota!

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Tenho recebido essa pergunta frequentemente dos leitores aqui do blog, assim como de alguns clientes, consultores e parceiros. A resposta é: não vai ser agora. Não vai ser mês que vem. Não vai ser tão já, a ponto de você considerar começar a fazer um trabalho com ele e quando sair a versão final você apenas precisar atualizar uns assemblies e modificar aqui e ali. A verdade é que muito pode mudar ainda. Se eu fosse chutar, acho que a Microsoft só entrega esse componente no último trimestre de 2008. Ia ser legal antes disso, para já termos o Tech Ed 2008 Brasil e o Web Days 2008 com versão final, mas acho que não vai dar tempo. Por enquanto vamos ter que ir curtindo o Preview 3 mesmo, que foi lançado agora.

Algumas partes importantes do componente ainda estão em aberto. Eles ainda precisam desenvolver diversas funções auxiliares para permitir um desenvolvimento mais rápido. Falta também o suporte ao AJAX e aos validadores (que com certeza não vão ser como os conhecemos), melhorar autenticação e autorização, cache, e mais um monte de coisa. O MVC atualmente, como está, está ainda muito cru, muito Unplugged. Não é fácil convencer um desenvolvedor que trabalha com Web Forms, validadores, AJAX, suporte ao designer, e tudo aquilo que amamos no ASP.Net, a simplesmente abandonar sua alta produtividade e o RAD. Até eles conseguirem chegar mais perto desse objetivo, não acho que lançam o MVC. E se lançarem, vão fazer um release mais ou menos, e vão lançar um update em pouco tempo. Acho melhor esperar.

Felizmente o Routing está perto de completar. O SP1 do Visual Studio 2008/.Net 3.5, que traz o Routing, já está em Beta 1 e quase lançado. O time do MVC estava trabalhando no Routing em grande parte, e agora se liberaram para por a mão onde realmente queriam, que era o MVC.

Como eu disse à todos que me perguntaram: sossegue e trabalhe com Web Forms por mais 6 meses. É melhor do que refazer um monte de código.


Postado na(s) categoria(s) ASP.Net MVC pelo Giovanni Bassi em 3 de junho de 2008 às 19:22 | Tags: , , ,

Ninguém avaliou. Dê sua nota!

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Pessoal, saiu o terceiro preview do ASP.Net MVC. Dêem uma olhada nos comentários do Hanselman, que vem com vídeos, do ScottGu, super completo, e do Phil Haack, com um exemplo com Northwind.

Eu ainda não vi. Depois comento por aqui o que eu achei.


Postado na(s) categoria(s) ASP.Net MVC pelo Giovanni Bassi em 28 de maio de 2008 às 22:20 | Tags: ,

Ninguém avaliou. Dê sua nota!

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Vi agora pouco no blog do ScottGu que o time do ASP.Net liberou o código fonte do ASP.Net MVC no Codeplex. Infelizmente não podemos alterar o fonte e redistribuir, eles querem que esse código sirva apenas como referência e nos permita corrigir algum bug, para impedir algum desenvolvimento fique parado. Para mim vai servir mais para ver como os caras fizeram mesmo o negócio funcionar.

Lembrando que o código do ASP.Net MVC ainda está em desenvolvimento e o framework está ainda em CTP, apesar de várias pessoas estarem pedindo um release o quanto antes (veja os comentários do Phil Haack no final deste seu post).

Assim como diz Scott Hanselman, ler código fonte é sempre bom (o cara chega a ter uma edição semanal de leitura de código fonte). Também recomendo.


Postado na(s) categoria(s) ASP.Net MVC pelo Giovanni Bassi em 21 de março de 2008 às 14:00 | Tags: ,

Ninguém avaliou. Dê sua nota!

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Quem é Giovanni Bassi

Giovanni Bassi Sou uma pessoa apaixonada por tecnologia e especificamente por .Net. Gerencio uma fábrica de software, gosto muito de arquitetura e engenharia de software, publico artigos e edito a .Net Magazine. Dou umas palestras e cursos de vez em quando, e quando dá tempo eu respiro um pouco. Mais detalhes nesta página.

Selos

Web Days 2008

MCPD

MCSD

.Net Magazine

Calendário

«  agosto 2008  »
seteququsedo
28293031123
45678910
11121314151617
18192021222324
25262728293031
1234567
Ver detalhamento de posts no calendário