WebParts – Personalização e Provider


No decorrer do artigo vimos como configurar as WebParts, conectá-las, editá-las, etc.. Só que, até este momento, o principal gerenciador de tudo isso é o controle WebPartManager. Mas, até então, não sabemos como são mantidas as modificações entre as múltiplas sessões do usuário e, principalmente, como e quando esses processos acontecem. Neste capítulo veremos esses processos de “baixo-nível” um pouco mais detalhadamente, porém tudo isso já está encapsulado pela plataforma e não exige muita programação para configurá-lo. De qualquer forma, não deixa de ser interessante analisá-lo.

O primeiro conceito que temos que nos atentar se resume aos tipos de escopos de páginas possíveis: User e Shared. Veremos detalhadamente através da tabela abaixo os detalhes destes tipos de escopos:

Escopo Descrição
User

O escopo a nível de usuário significa que as mudanças e a personalização serão para um usuário específico.

Shared

O escopo compartilhado permitirá que todas as alterações feitas a nível de página sejam compartilhadas entre todos os usuários que a acessam.

Já o segundo conceito é a visibilidade dos controles. Isso irá determinar se um determinado controle está visível para um usuário ou para todos os usuários. Cada controle WebPart na página é um controle que é compartilhado, visível a todos os usuários que acessam a página; ou um controle per-user é visível somente a um usuário específico. A visibilidade é determinada de acordo com a forma que o controle é adicionado à página. Se o controle é adicionado via markup (diretamente no código HTML), ele sempre será um controle compartilhado. Se o controle é adicionado na aplicação via código ou se o usuário o seleciona em um catálogo (controles dinâmicos), a visibilidade é determinado pelo escopo corrente da personalização da página. Se a página estiver em escopo Shared, o controle dinamicamente criado será compartilhado; se a página estiver em escopo User, o controle será exclusivo daquele usuário que o criou.

O terceiro e último conceito é o escopo de propriedade. Quando você cria uma propriedade personalizada (denotada com o atribute Personalizable), você pode definir o escopo de personalização para a propriedade em questão para Shared ou User, sendo User o padrão. Isso fornecerá um controle detalhado sobre como podemos personalizar por todos os usuários e ainda podemos personalizar somente por usuários autorizados quando o escopo da página estiver definido como Shared.

Juntos, esses conceitos de escopo de personalização de página, visibilidade de controle e escopo de personalização de propriedade criam um conjunto de opções de como que os controles WebParts possam ser visualizados e personalizados pelos usuários. A tabela abaixo sumariza como estes controles se comportam quando os usuários personalizam esses controles em vários escopos:

Visibilidade de Controle Página em escopo compartilhado Página em escopo de usuário
Controle compartilhado

Um usuário autorizado pode personalizar propriedades em escopo User e Shared para todos os usuários.

No caso de controles adicionados dinamicamente, um usuário autorizado pode permanentemente fechar o controle para todos os usuários.

Já utilizando controles estáticos, eles não podem ser excluídos, embora possa ser fechado por um usuário autorizado para todos os usuários.

Usuários individuais não podem personalizar as propriedades definidas com o escopo compartilhado. Eles podem somente personalizar as propriedades definidas com o escopo de usuário.

Estes usuários podem fechar um controle compartilhado, que será adicionado à um Page Catalog, mas não poderá permanentemente excluí-lo.

Controle personalizado por usuário

Este controle não pode ser personalizado com a página em escopo compartilhado porque o controle não aparecerá toda vez na página, somente aparecerá quando a página estiver em escopo de usuário.

Usuários individualmente podem personalizar as propriedades dos controles em ambos escopos: User e Shared, porque a instância do controle é exclusiva/privada, podendo também excluir o controle permanentemente.

Depois de entendidos os conceitos, temos ainda dois componentes importantíssimos que possibilitam a personalização que são o WebPartManager e o WebPartPersonalization. O primeiro, WebPartManager, como já sabemos, gerencia todas as WebParts disponíveis na página, habilitando e gerenciando o ciclo de vida dos dados da personalização. Ele contém uma propriedade denominada Personalization, que expõe um objeto do tipo WebPartPersonalization, que disponibiliza as seguintes (auto-explicativas) propriedades: ProviderName, InitialScope e Enabled; já o WebPartPersonalization implementa a lógica necessária para realizar algumas ações referentes a personalização de “baixo-nível”.

A classe WebPartPersonalization armazena internamente um objeto do tipo PersonalizationProvider que, durante a execução, armazena uma referência ao provider especificado no arquivo Web.Config. Essa arquitetura faz parte de um padrão criado pela Microsoft denominado Provider Model, que já falamos sobre ele neste artigo. O ASP.NET fornece um provider para que os dados sejam salvos no banco de dados SQL Server. A classe concreta chama-se SqlPersonalizationProvider e, podemos ver através da imagem abaixo a hierarquia das classes, desde a abstrata ProviderBase até a classe concreta para SQL Server. Se quisermos criar um provider de personalização customizado basta herdarmos da classe abstrata PersonalizationProvider e customizarmos para o repositório desejado.

Figura 1 – Arquitetura de Provider Model para personalização.

Além das configurações que podem ser realizadas no controle WebPartManager, ainda há outras configurações, não menos importantes, a serem realizadas no arquivo Web.Config. Dentro do mesmo, mais especificamente dentro do elemento webParts, personalization há um sub-elemento chamado authorization, onde podemos especificar quais usuários (ou papéis) podem entrar e fazer parte de uma página que contém escopo compartilhado. Ainda no elemento authorization há um atributo denominado verbs, que permite definirmos dois valores:

Verbo Descrição
enterSharedScope

Indica se o usuário ou papel (role) pode acessar uma página definida com escopo compartilhado.

modifyState

Indica se o usuário ou papel (role) é capaz de modificar os dados de personalização para o escopo corrente.

Para exemplificar a configuração a ser realizada no arquivo Web.Config, analise o código abaixo. Repare que proibimos todos os usuários (deny) de entrar em um escopo compartilhado e de modificar os dados de personalização (note o atributo verbs). Depois disso, permitimos o acesso a estas funcionalidades apenas a usuários que estão contidos dentro do papel de Administradores.

<webParts>
  <personalization>
    <authorization>
      <allow roles="Administradores" verbs="enterSharedScope, modifyState" />
      <deny users="*" verbs="enterSharedScope, modifyState" />            
    </authorization>
  </personalization>
</webParts>

Definido no arquivo Web.Config os usuários ou papéis que terão as devidas permissões, podemos a qualquer momento fazer a transição entre o escopo de usuário (que é o padrão) para o escopo compartilhado. Tudo isso é possível através do método ToogleScope da classe WebPartPersonalization. Mas não podemos invocar este método sem antes verificar se o usuário corrente tem ou não permissão para entrar neste escopo compartilhado. O trecho de código abaixo ilustra esse processo de transição entre os escopos:

protected override void OnInit(EventArgs e)
{
    base.OnInit(e);
    if (this.WebPartManager1.Personalization.Scope == PersonalizationScope.User
        && WebPartManager1.Personalization.CanEnterSharedScope)
    {
        this.WebPartManager1.Personalization.ToggleScope();
    }
}

Como falamos acima, é importante verificar se o usuário tem ou não permissão para alternar entre os escopos. E para possibilitar essa verificação, a propriedade CanEnterSharedScope retorna um valor booleano indicando se o usuário está autorizado a entrar no escopo compartilhado.

Personalização de Propriedades

Como você já deve ter reparado, em um dos capítulos anteriores fizemos o uso de um atributo chamado PersonalizableAttribute em uma determinada propriedade de um UserControl. Esse atributo permite-nos especificar propriedades que devem ter seus valores persistidos através da personalização. Este atributo tem uma sobrecarga em seu construtor que permite informarmos um enumerador do tipo PersonalizationScope, indicando qual é o escopo da personalização. Este enumerador provê duas opções: Shared e User (padrão), acima explicadas. Abaixo é mostrado um exemplo de como criar um propriedade e denotá-la com o atributo Personalizable:

[
    WebBrowsable,
    WebDisplayName("Cor da Barra de Navegação"),
    WebDescription("Cor que aparecerá como Background da Barra de Navgegação"),
    Personalizable(PersonalizationScope.Shared)
]
public string CorBarraNavegacao
{
    get
    {
        return this.BarraNavegacao.BgColor;
    }
    set
    {
        this.BarraNavegacao.BgColor = value;
    }
}

Interface IPersonalizable

Se falarmos de personalização de WebParts, jamais poderíamos deixar de abordar a interface IPersonalizable. Esta interface fornece dois métodos e uma propriedade que nos permitirá ter um maior controle durante a persistência e o carregamento de dados a serem personalizados.

Como dissemos, esta interface nos fornece os seguintes membros: Load, Save e IsDirty. O método Load é invocado quando os dados de personalização são extraídos do repositório para a aplicação; o método Save permite-nos interceptar o processo de persistência dos dados no repositório; finalmente, a propriedade IsDirty retorna um valor booleano indicando se os dados do controle sofreram ou não alguma alteração.

Os métodos Load e Save tem em sua assinatura um parâmetro do tipo PersonalizationDictionary, que nada mais é do que uma coleção (key/value) de objetos do tipo PersonalizationEntry. Com isso podemos, em qualquer um dos momentos, acessar a coleção de dados a serem persistidos ou carregados e manipular da maneira que desejarmos. O uso desta técnica é geralmente utilizado quando não precisamos expor a propriedade com o atribute Personalizable já que o valor é definido internamente, ou seja, dentro do próprio controle. Através do exemplo abaixo, veremos como implementar esta interface em um UserControl:

private bool _isDirty;

public bool IsDirty
{
    get
    {
        return this._isDirty;
    }
}

public void Load(PersonalizationDictionary state)
{
    PersonalizationEntry entry = state["TextBoxValue"] as PersonalizationEntry;
    if (entry != null)
    {
        this.txtValor.Text = entry.Value.ToString();
    }
}

public void Save(PersonalizationDictionary state)
{
    state["TextBoxValue"] = 
        new PersonalizationEntry(
            this.txtValor.Text.Trim(), 
            PersonalizationScope.User);
}

protected void txtValor_TextChanged(object sender, EventArgs e)
{
    this._isDirty = true;
}

Analisando o código acima, podemos ver que no evento TextChanged de um determinado controle TextBox que está com a propriedade AutoPostBack definido como True, é definido True para o membro _isDirty, que é exposto pela propriedade IsDirty. O valor desta propriedade irá determinar se o método Save deverá ou não ser disparado para que possamos interceptar o processo de persistência e definirmos anexar valores na coleção fornecida como parâmetro para tal método.

Reinicializando o Estado da Página

A infra-estrutura ainda possibilita a reinicialização do estado das WebParts de uma determinada página, ou seja, permite que você volte ao ponto inicial, como ela foi inicialmente definida. Geralmente os métodos que possibilitam isso são baseados em escopos, onde você pode determinar qual dos escopos quer reinicializar. Para analisar os métodos disponíveis para reinicialização de estado, analise a classe estática PersonalizationAdministration e seus respectivos métodos.

WebParts.zip (293.75 kb)

Anúncios

Deixe uma resposta

Preencha os seus dados abaixo ou clique em um ícone para log in:

Logotipo do WordPress.com

Você está comentando utilizando sua conta WordPress.com. Sair / Alterar )

Imagem do Twitter

Você está comentando utilizando sua conta Twitter. Sair / Alterar )

Foto do Facebook

Você está comentando utilizando sua conta Facebook. Sair / Alterar )

Foto do Google+

Você está comentando utilizando sua conta Google+. Sair / Alterar )

Conectando a %s