Otimizando a compilação

Quando fazemos alguma mudança no diretório bin, App_Code ou no arquivo Global.asax, toda a aplicação ASP.NET será recompilada. Para sites pequenos, isso não tem muitos problemas, já que não há muitos arquivos/recursos a serem compilados. Já quando temos um site com várias páginas, esse processo pode se tornar muito lento, principalmente na primeira requisição, que é o onde a compilação irá ocorrer.

O SP1 do .NET Framework 3.5 inclui um novo atributo chamado optimizeCompilations, dentro do elemento compilation. Quando esse atributo estiver definido como False (configuração padrão), qualquer mudança provocará a recompilação total do site; já quando voce, explicitamente, definí-lo como True, somente os arquivos afetados pela mudança serão recompilados. Abaixo temos o exemplo da utilização deste novo atributo:

<compilation optimizeCompilations=”true”>

Core Services no ASP.NET 4.0

Além de algumas novidades que já foram reportadas neste post, o ASP.NET 4.0 trará ainda uma série de funcionalidades muito interessantes e, entre elas, teremos:

OutputCaching Extensível

Quando utilizamos o OutputCaching em uma página, a primeira requisição a executará, e antes de devolver o conteúdo para o cliente, o resultado é armazenado na memória do servidor Web, e com isso, futuras requisições utilizarão esse conteúdo ao invés de reprocessar a página completamente. O ASP.NET 4.0 fornece uma forma altamente flexível para conseguirmos customizar o repositório de caching trabalhando com providers, assim como já acontece nas principais funcionalidades do ASP.NET atual.

Auto-Start de Aplicações

Todos sabemos que as aplicações ASP.NET tem um delay na primeira requisição, que se deve ao fato de efetuar a compilação da mesma. A partir do ASP.NET 4.0, em conjunto com o IIS 7.5, teremos uma funcionalidade chamada de auto-start. Ao configurar esta funcionalidade em uma aplicação, o IIS enviará uma mensagem ao ASP.NET para que a sua aplicação faça o processo necessário para deixá-la pronta para ser consumida. Tudo isso ocorre no momento em que o IIS/AppPool ainda não aceita requisições.

O mais interessante é que ainda podemos interceptar este evento, implementando o método Preload da Interface IProcessHostPreloadClient. Nele podemos fazer outras “pré-inicializações” que antes eram feitas sob demanda.

Redirecionamento Permanente

Como já comentado aqui, agora teremos um método chamado RedirectPermanent que efetuará esse tipo de redirecionamento.

Compressão das variáveis de Sessão

Quando utilizamos variáveis de sessão, elas são armazenadas na memória do servidor onde a aplicação está sendo executada (In-Process). Além disso, temos duas outras possibilidades que é o armazenamento diretamente no SQL Server ou um servidor exclusivo para o armazenamento das variáveis sessão (Out-of-Process). Nestas duas últimas opções, há um overhead extra, que ocorre justamente porque o objeto responsável que armazena as informações, deverá ser serializado antes de enviado para o destino remoto.

Dependendo do que é armazenado dentro das variáveis de sessão, esse processo pode custar muito caro, tanto em termos de comunicação quanto em termos de memória ou espaço físico. A partir do ASP.NET 4.0, o elemento sessionState irá possuir um novo atributo chamado compressionEnabled. Ao definí-lo como True, o ASP.NET fará o processo necessário para comprimir e descomprimir os dados, utilizando a classe GZipStream.

Para aqueles que quiserem mais informações sobre as novas funcionalidades, consulte este documento.

ASP.NET Development Server parou de funcionar

Com a instalação de uma atualização que a Microsoft lliberou, o arquivo hosts (C:WindowsSystem32driversetc) pode ter sido alterado, removendo a entrada que tem o apontamento do IP 127.0.0.1 para localhost, fazendo com que os projetos ASP.NET que usam o servidor interno do Visual Studio .NET para hospedar as aplicações deixem de funcionar. Com isso, ao rodar essas aplicações, voce receberá a seguinte mensagem: “Internet Explorer cannot display the webpage”.

Como já era de se esperar, basta readicionar esta linha no arquivo para que tudo volte ao normal, assim como é mostrado abaixo:

127.0.0.1       localhost

DBAuthorization – Parte 10 – Conclusão

Finalmente chegamos na conclusão desta série. A partir deste momento você tem todas as políticas de acesso as páginas dentro do banco de dados, com uma arquitetura flexível e que pode ser estendida para ser suportada por outros repositórios.

Uma vez que o provider foi criado, sempre que nós precisamos das informações, seja para aplicar a autorização durante a execução ou pelas telas de gerenciamento das informações, sempre utilizamos o provider para isso (classe DBAuthorization), o que torna a aplicação e a API totalmente independente de qual fonte de dados estamos utilizando para armazenar essas informações.

É importante dizer também que, assim como a UrlAuthorization, a DBAuthorization avalia as permissões de forma sequencial, ou seja, a ordem em que elas aparecerem cadastradas no banco de dados será a ordem de avaliação durante a execução. Neste momento não temos nenhuma forma de reordenação dos registros, mas isso pode ser facilmente implementado. Um boa prática aqui é sempre você ir cadastrando em uma ordem coerente, ou seja, negue o acesso anônimo para um diretório como um todo mas, dentro dele, customize o acesso à algumas seções de acordo com os papéis.

Outra semelhança que o DBAuthorizationModule possui em relação ao UrlAuthorizationModule é que faz uso da propriedade User da classe HttpContext. Essa propriedade retorna a instância de uma classe que implementa a interface IPrincipal e, independentemente do tipo de autenticação que está utilizando (Forms (GenericPrincipal) ou Windows (WindowsPrincipal)), ele sempre irá trabalhar de forma genérica. Utilizará a propriedade IIdentity para determinar o nome do usuário e o método IsInRole para avaliar se o usuário faz ou não parte de um determinado papel/grupo.

Para efeitos de centralização e reusabilidade da API, você pode instalar essa DLL dentro do GAC (Global Assembly Cache) e registrar a seção “dbAuthorization” no arquivo machine.config. Esta técnica evitará com que todas as aplicações que desejam fazer uso deste recurso, não precisem explicitamente fazer o registro.

Para finalizar, todo esse projeto não foi implementando em um ambiente real. Os testes foram locais e, se desejar colocá-lo em um ambiente de produção, chamo a atenção para que você refaça os testes, analisando todas as possibilidades necessárias para garantir o bom funcionamento dele.

Quero também agradecer imensamente ao Luis Abreu, expert em tecnologias Microsoft, que revisou e me deu dicas extremamente importantes para ajudar na elaboração desta série. O código para download está no seguinte endereço: http://www.israelaece.com/BlogEngine.Web/file.axd?file=2009%2f4%2fDBAuthorization.zip.

DBAuthorization – Parte 9 – Interface de Administração

Nos posts anteriores analisamos detalhadamente como devemos proceder para criar a infraestrutura necessária, e para efetuar a autorização com as informações armazenadas em uma base de dados. Sem telas de administração destas informações, teríamos que recorrer diretamente as ferramentas do próprio banco de dados para inserir as informações.

Para facilitar, criei também duas telas: ViewAllRules.aspx e AddRule.aspx. A primeira delas exibe uma lista contendo todas as políticas cadastradas, exibindo o caminho (path), ação e tipo, dando também a opção de exclusão. A imagem abaixo exibe essa tela, podendo ser customizada para ter uma melhor aparência:

Basicamente, no evento Load da página invoco o método GetAllRules a partir do provider (classe DBAuthorization) e, com o retorno deste método (DBAuthorizationRuleCollection) carrega o controle DataList. O código para carregar os dados é bem simples:

private void BindRules()
{
    this.DataList1.DataSource = DBAuthorization.GetAllRules();
    this.DataList1.DataBind();
}

Já a segunda página, AddRule.aspx, disponibiliza um formulário com os devidos campos para a criação de uma nova política. Esse formulário já está configurado com alguns DropDownList’s para assegurar que o usuário que está cadastrando a política escolha apenas um dos tipos ou ações suportadas. Essa página é exibida abaixo:

O único código que temos aqui é a inserção da regra no evento Click do botão “Add Rule”, código qual é mostrado abaixo:

DBAuthorization.AddRule(
    new DBAuthorizationRule()
    {
        Action = Helper.ParseEnum<DBAuthorizationRuleAction>(this.Action.SelectedValue),
        Data = Helper.ExtractCollectionFromString(this.Data.Text.Trim()),
        Path = this.Path.Text.Trim(),
        Type = Helper.ParseEnum<DBAuthorizationRuleType>(this.Type.SelectedValue)
    });

Ao caminho (path) não necessariamente precisa ser uma página ASPX, mas um diretório. Isso pode ajudar quando você precisa proteger um diretório todo. Utilize a página quando precisar de um refinamento da autorização, concedendo acesso específico à um papel ou usuário. Como a busca pelo path está baseado na propriedade Path da classe HttpRequest, a propriedade Path da classe DBAuthorizationRule deve seguir o padrão de URL absoluta, como por exemplo: “/App/Diretorio/Pagina.aspx” ou apenas “/App/Diretorio/”.

Essas telas são simplesmente páginas ASPX que fazem uso do API DBAuthorization para exibir ou criar novas políticas de acesso. Como elas fazem parte de um projeto específico, essas telas não são reutilizáveis por várias aplicações. Fica sob responsabilidade do desenvolvedor criar ou não as telas nas aplicações que deseja fazer uso desta funcionalidade.

DBAuthorization – Parte 8 – Configuração do arquivo Web.config

No post anterior acoplamos o módulo DBAuthorizationModule e removemos o módulo UrlAuthorizationModule da execução da aplicação. Isso fará com que a avaliação das políticas seja feita utilizando o provider, que tem o papel de disponibilizar as informações para o módulo e para a aplicação.

Mas as configurações no arquivo Web.config não se resumem a isso. Além das configurações do Membership e Roles, ainda precisamos registrar o provider responsável pela autorização no Web.config. A criação da classe que representa essa seção já foi discutida no artigo em que demonstro como criar um provider customizado. Esse artigo pode ser acessado a partir deste endereço e vou assumir que você tenha o devido conhecimento nisso.

No código abaixo limitei as configurações relevantes do provider, como o registro da seção, a conexão com o banco de dados e a configuração do provider em si. Note que o escolhido foi o “SqlAuthorizationProvider”:

<?xml version=”1.0″?>
<configuration>
    <configSections>
        <section
            name=”dbAuthorization”
            type=”ProjetandoNET.Web.Configuration.DBAuthorizationSection, ProjetandoNET”
            requirePermission=”false” />
    </configSections>
    <connectionStrings>
        <clear/>
        <add
            name=”SqlConnectionString”
            connectionString=”Data Source=.;Initial Catalog=DB;Integrated Security=SSPI;”
            providerName=”System.Data.SqlClient” />
    </connectionStrings>
    <dbAuthorization defaultProvider=”SqlAuthorizationProvider”>
        <providers>
            <add
                name=”SqlAuthorizationProvider”
                type=”ProjetandoNET.Web.Security.SqlAuthorizationProvider, ProjetandoNET”
                applicationName=”WebTeste”
                connectionStringName=”SqlConnectionString”
                storeRulesInCache=”true”
                commandTimeout=”40″ />
        </providers>
    </dbAuthorization>
</configuration>

Assim como na configuração do módulo, o registro da seção que criamos e também os tipos dos providers referentes à autorização também devem contemplar o nome completo (namespace + Assembly). Você pode utilizar cada elemento add para adicionar quantos providers forem necessários mas, em runtime, o ASP.NET utilizará o provider especificado no atributo defaultProvider.

DBAuthorization – Parte 7 – DBAuthorizationModule

Com o post anterior provemos uma boa performance, garantindo que a mesma informação seja compartilhada entre todos os usuários de uma aplicação específica. Além disso, em posts anteriores analisamos como extrair os dados da fonte de dados mas, tudo o que fizemos até então, é a manipulação de dados, mas a regra para validar se o usuário atual possui ou não direito de acesso não foi definida.

Todas as funcionalidades que falamos no primeiro post desta série estão acopladas ao pipeline do ASP.NET através de módulos (IHttpModule). Se analisarmos o arquivo Web.config do servidor (aquele que está dentro do diretório do .NET Framework), veremos os módulos vinculados à execução da aplicação:

<httpModules>
    <add
        name=”WindowsAuthentication”
        type=”System.Web.Security.WindowsAuthenticationModule”/>
    <add
        name=”FormsAuthentication”
        type=”System.Web.Security.FormsAuthenticationModule”/>
    <add
        name=”RoleManager”
        type=”System.Web.Security.RoleManagerModule”/>
    <add
        name=”UrlAuthorization”
        type=”System.Web.Security.UrlAuthorizationModule”/>
    <add
        name=”FileAuthorization”
        type=”System.Web.Security.FileAuthorizationModule”/>
</httpModules>

Os módulos de autenticação são executados de acordo com a opção escolhida no arquivo Web.config (Forms ou Windows). Para autorização, a classe HttpApplication fornece um evento chamado AuthorizeRequest, que é disparado quando chega o momento de determinar a autorização da página requisitada. Os módulos “assinam” esse evento, e são notificados quando ele ocorre e, com isso, executam as verificações necessárias para determinar se o usuário possui ou não os privilégios necessários para acessar a página solicitada.

A UrlAuthorization é a responsável por efetuar essa verificação levando em conta as políticas de acesso que colocamos no arquivo Web.config e, como sabemos, se alteradas forçam o processo do ASP.NET ser reciclado, o que queremos evitar. Como não vamos mais levar em conta as configurações de políticas de acesso que estão no arquivo de configuração, devemos remover este módulo da execução mas, antes disso, ainda é necessário criarmos o nosso.

DBAuthorizationModule é uma classe que implementa a Interface IHttpModule e também assina o evento AuthorizeRequest. No nosso caso, temos que avaliar se o usuário possui ou não privilégio de acesso consultando o provider anteriormente criado. O provider, por sua vez, irá retornar as políticas do cache ou efetuar a busca no banco de dados.

Depois que o provider devolver as políticas definidas, temos que aplicar a regra necessária para conceder ou negar o acesso para o usuário corrente. Mas antes de efetivamente executar essa tarefa, precisamos analisar a propriedade SkipAuthorization da classe HttpContext. Essa propriedade retorna um valor booleano indicando se a autorização deve ou não ser avaliada. Um exemplo disso é quando você solicita a página de Login. Essa página não deve sofrer nenhuma espécie de autorização, já que todos devem acessá-la. Caso essa propriedade retorne False, então devemos avaliar os privilégios do usuário. O código abaixo ilustra o módulo:

public class DBAuthorizationModule : IHttpModule
{
    public void Init(HttpApplication context)
    {
        context.AuthorizeRequest += new EventHandler(OnEnter);
    }

    private void OnEnter(object sender, EventArgs e)
    {
        HttpApplication application = (HttpApplication)sender;
        HttpContext context = application.Context;

        if (!context.SkipAuthorization)
        {
            if (!IsUserAllowed(context.User, context.Request.Path, context.Request.RequestType))
            {
                context.Response.StatusCode = 401;
                context.Response.StatusDescription = “Unauthorized”;
                application.CompleteRequest();
            }
        }
    }

    public static bool IsUserAllowed(IPrincipal principal, string requestedPath, string verb)
    {
        return DBAuthorization.GetAllRulesByPath(requestedPath).IsUserAllowed(principal, requestedPath, verb);
    }
}

Para avaliar as políticas, criei um método estático chamado IsUserAllowed que recebe como parâmetro o usuário corrente, a página (path) requisitada e o verbo (GET ou POST). Esse método recorre ao provider para recuperar a coleção de regras definidas e, em seguida, invoca o método IsUserAllowed da classe DBAuthorizationRuleCollection informando os mesmos parâmetros. É dentro deste método que toda a “mágica” ocorre, e que por questões de espaço, não será exibida aqui.

Caso os métodos IsUserAllowed retornem False, definimos o código de status de HTTP como 401 (Unauthorized) e invocamos o método CompleteRequest da classe HttpApplication, que obriga o ASP.NET a dar um “bypass” em todos os eventos da classe HttpApplication, direcionando a requisição para o evento EndRequest.

Com o módulo criado, então é necessário adicioná-lo à execução. Mas antes disso, como não faremos uso da Url Authorization, precisamos também removê-la. Dentro do arquivo Web.config da aplicação temos uma seção chamada httpModules. Essa seção permite alistarmos todos os módulos que serão utilizados pela aplicação e, a remoção do módulo “UrlAuthorization” se faz necessária porque em runtime ele mescla os módulos do Web.config do servidor com o da aplicação. Abaixo temos a configuração necessária:

<httpModules>
    <remove
        name=”UrlAuthorization”/>
    <add
        name=”DBAuthorizationModule”
        type=”ProjetandoNET.Web.Security.DBAuthorizationModule, ProjetandoNET”/>
</httpModules>

Note que o tipo (atributo type do elemento add) deve refletir o nome completo da classe, ou seja, incluindo os possíveis namespaces e também o nome do Assembly. As configurações do arquivo Web.config da aplicação não param por aí. Veremos mais detalhes no próximo post desta série.

DBAuthorization – Parte 6 – Caching

No post que vimos anteriormente falamos a respeito da infraestrutura necessária para criar uma solução flexível, visando ter uma independência de base de dados e que nos atendeu perfeitamente. O problema é que o acesso a qualquer fonte de dados (IO), seja banco de dados ou sistema de arquivos é muito custoso e, se fizermos isso durante toda e qualquer requisição para extrair as políticas de autorização, podemos ter problemas relacionados à performance da aplicação.

Quando habilitamos o uso das Roles do ASP.NET, então temos uma configuração que permite o armazenamento dos papéis do usuário em cookie e, com isso, apenas quando ele não for detectado é que o runtime do ASP.NET irá até a base para extrair os papéis do respectivo usuário. Essa solução é interessante, já que os papéis são exclusivos para cada um dos usuários. No caso das políticas de acesso às páginas da aplicação, isso refere-se à um recurso global e que não deve ser armazenado usuário por usuário.

Para evitar o round-trip excessivo ao provider (que no nosso caso é a base de dados), podemos criar uma variável global do tipo DBAuthorizationRuleCollection para armazenar todas as políticas de acesso da aplicação corrente. Com isso, apenas a primeira requisição fará o caminho completo, indo até o provider configurado, extraindo as informações e colocando-as no cache. A partir deste momento, as requisições subsequentes passam a utilizar este cache.

Uma vez que colocamos algum objeto no cache, passamos a ter um outro – pequeno – problema. Por quanto tempo isso vai “viver”? É importante lembrar que vamos criar uma área administrativa em que um usuário poderá customizar essas políticas e, qualquer mudança que ele fizer, devemos invalidar o cache existente. Talvez alguns querem alterar as políticas, mas não vê nenhum problema se essas mudanças não forem aplicadas imediatamente. Para atender a todos, criei um evento chamado DataChanged na classe DBAuthorizationProvider. Esse evento é disparado sempre quando uma nova política é criada ou excluída, e tem a finalidade de informar à aplicação que algo foi mudado, dando oportunidade para ela decidir se mantém ou não o cache.

Esse evento possui um argumento específico, chamado CachingRulesEventArgs. Essa classe tem uma propriedade booleana chamada ClearCache que, por padrão, é True e determina a limpeza do cache. Sendo assim, o momento ideal para assinar este evento é no evento Application_Start, acessível a partir do arquivo Global.asax. O exemplo abaixo ilustra como podemos determinar a limpeza ou não do cache, caso algum dado seja alterado durante a execução da aplicação:

DBAuthorization.Provider.DataChanged += (source, args) => args.ClearCache = true;

Como o padrão é True, somente faz sentido utilizar este código se quiser manter as políticas atuais em cache ou efetuar alguma tarefa customizada. A classe DBAuthorizationProvider possui um método virtual chamado OnDataChanged e, é dentro deste método que ela analisa se a aplicação se vinculou ou não ao evento, e caso verdadeiro o dispara. Finalmente, se a propriedade ClearCache retornar True, essa classe efetuará a limpeza do cache.

CacheManager é a classe estática responsável por gerenciar o cache e que é compartilhada por toda a aplicação. Além de manter a coleção das políticas da aplicação, também possui um objeto do tipo ReaderWriterLockSlim (namespace System.Threading) que gerencia o acesso concorrente ao cache. Esse tipo de objeto garante múltiplas threads para leitura ou o acesso exclusivo para escrita.

É importante dizer que, por mais custoso que seja, o desenvolvedor pode optar por querer sempre consultar a base de dados e, justamente por isso, que criei uma propriedade booleana chamada StoreRulesInCache, que indica ao runtime se os dados devem ou não serem armazenados no cache, sendo o padrão True.

DBAuthorization – Parte 5 – Provider

Os tipos que vimos no post anterior serão utilizados pelo módulo para determinar se a página requisitada possui ou não permissão de acesso. Mas antes disso ainda há um passo extremamente importante, que é justamente a manipulação das informações do repositório que, no nosso caso, será o banco de dados, mais precisamente o SQL Server 2005.

Para seguir as boas práticas do ASP.NET e tornar esse processo independente de fonte de dados, podemos recorrer a criação de um provider customizado (este assunto já foi esgotado neste artigo). Isso irá permitir criarmos uma infraestrutura flexível, permitindo que outros desenvolvedores possam criar classes para abstrair o acesso à outros repositórios, como Oracle ou até mesmo à um  arquivo Xml, como comentado anteriormente. Vale lembrar que as principais funcionalidades do ASP.NET, como o Membership, Roles, Profile, etc., estão baseadas nesta arquitetura.

Para entender exatamente como funciona esta arquitetura, consulte o artigo acima. Neste post vou abordar os tipos base que criei para a criação do provider e também a classe necessária para a manipulação dos dados de autorização dentro do SQL Server.

Em primeiro lugar, foi criado uma classe abstrata chamada DBAuthorizationProvider. Esta classe define a estrutura de métodos e propriedades que todo o provider concreto deverá ter para funcionar. Basicamente temos métodos que fazem a manipulação das informações da fonte de dados, sendo ela qual for, expondo ou recebendo os tipos que falamos anteriormente (DBAuthorizationRule e DBAuthorizationRuleCollection). Isso permitirá criar tipos concretos como SqlAuthorizationProvider (abordado nesta série), OracleAuthorizationProvider ou XmlAuthorizationProvider. Outra definição importante que essa classe expõe é a propriedade ApplicationName que, como todo provider, é necessária para possibilitar a utilização da mesma fonte de dados por múltiplas aplicações, e também deve ser considerada sempre que for efetuar alguma operação no banco de dados. Esta classe ainda fornece métodos para o gerenciamento de caching, que serão abordados futuramente.

O exemplo vem com uma implementação concreta deste provider, que chamei de SqlAuthorizationProvider. Essa classe é a implementação do provider para utilização com SQL Server. Dentro desta classe utilizamos os tipos expostos pelo namespace System.Data.SqlClient para manipular a fonte de dados, utilizando as Stored Procedures que foram mostradas na Parte 3 desta série.

Depois desta estrutura, ainda temos a classe estática DBAuthorization. Como já era de se esperar, essa classe terá todos os membros estáticos e servirá como uma espécie de “ponte” entre a aplicação e o provider especificado no arquivo de configuração. Ela fornece uma propriedade chamada Provider que, por sua vez, retorna a instância do provider (DBAuthorizationProvider) atualmente selecionado. É importante notar que esta classe fornece todos os métodos estipulados pela classe DBAuthorizationProvider mas, invoca os respectivos métodos a partir da propriedade Provider que, consequentemente, irá delegar a chamada para o objeto definido no momento.

Para extrair o provider selecionado no arquivo de configuração, essa classe invoca dentro do construtor estático o método Initialize. Aqui não há necessidade de efetuar algum tipo de “lock” pois, por padrão, o construtor estático já está protegido contra o acesso concorrente neste trecho do código. Para finalizar, a imagem abaixo ilustra a relação entre as classes que foram abordadas neste post:

DBAuthorization – Parte 4 – Estrutura dos Tipos

No post anterior exibi a estrutura necessária para armazenamento das políticas no banco de dados. Da mesma forma, a aplicação também precisa definir alguns tipos (enumeradores, classes, etc.) para garantir que a programação/consumo desta API seja realizada de forma consistente.

Neste post não será discutido na íntegra cada uma das classes, pois isso será feito no momento específico e, além disso, há classes que foram criadas que são utilizadas como “helpers” e que não serão abordadas aqui. Vamos focar apenas nos tipos que representam a estrutura necessária para fazer o recurso funcionar.

Há dois enumeradores chamados DBAuthorizationRuleAction e DBAuthorizationRuleType. O primeiro fornece duas opções autoexplicativas: Deny e Allow. Já o segundo determina os tipos disponíveis, onde efetivamente a política será aplicada: Users, Roles ou HttpVerbs. A combinação destes dois valores ainda exigirá um valor adicional, que são os usuários, papéis ou verbos que poderão ou não acessar o recurso em questão.

Uma outra classe que tem o papel importante nesta funcionalidade é a DBAuthorizationRule. Esta classe representa uma política e, para isso, ela possui as seguintes propriedades (entre parênteses temos o tipo delas): Action (DBAuthorizationRuleAction), Type (DBAuthorizationRuleType), PathId (Guid), RuleId (Guid), Path (String) e Data (StringCollection). Além destas propriedades, ainda temos as propriedades Everyone (Boolean) e Anonymous (Boolean), que são somente leitura. A propriedade Everyone retorna um valor booleano indicando se o caractere “*” está definido na propriedade Data, enquanto a propriedade Anonymous também retorna um valor booleano indicando a existência do caractere “?”. Essas duas propriedades estão fortemente relacionadas ao tipo, ou seja, o caractere “?” somente faz sentido quando é usado em conjunto com o tipo DBAuthorizationRuleType.Users.

Para finalizar, ainda temos a classe DBAuthorizationRuleCollection que, como o próprio nome diz, é uma coleção de elementos do tipo DBAuthorizationRule. Para efeitos de boas práticas, esta classe herda diretamente da classe Collection<T>, apesar de não haver a necessidade de interceptar qualquer mudança na coleção. A imagem abaixo ilustra graficamente os tipos discutidos neste post