Este artigo foi traduzido por máquina.

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

Cutting Edge

Gerenciando a entrega de conteúdo dinâmica no Silverlight, parte 2

Dino Esposito

Conteúdo

Motivação para um cache permanente
Fundamentos do armazenamento isolado
API do armazenamento isolado
Criar um cache permanente de pacotes
Diretivas de expiração
Juntando tudo
Algumas anotações final

Último mês eu abordou como atender um aplicativo de Silverlight algum conteúdo gerado dinamicamente na inicialização e até mesmo em um cenário por demanda. Muitos exemplos existem aí para mostrar a você como usar a classe do WebClient e seu modelo de chamada assíncrona para baixar um recurso baseados em URL. Em particular, focaliza o que demora para baixar um pacote XAP que inclui o XAML e código gerenciado (consulte aEdição de janeiro de 2009 de Cutting Edge.

A idéia básica é que você baixe um fluxo (zipada) e, em seguida, extrair qualquer assembly que você precisa. Em seguida, você pode criar qualquer classe que você precisa que está contido no assembly. A classe é um controle de usuário XAML — uma parte inteira de uma árvore visual do XAML — que você pode acrescentar a quaisquer espaços reservados no atual XAML documento modelo de objeto do (DOM Document Object Model).

Para o navegador, quaisquer recursos XAP baixados são totalmente indistinguíveis de qualquer outro tipo de recurso. Portanto, o navegador armazena em cache um pacote XAP assim como qualquer outro recurso baixado. Esse mecanismo interno oferece um primeiro nível de otimização que economiza repetido viagens de ida e volta para obter o mesmo pacote repetidas. A classe WebClient — o núcleo do componente downloader abordado coluna do mês passado — se baseia no mecanismo de conectividade do navegador e não baixar recursos disponíveis localmente e não expirado ainda.

No final do dia, você tem um componente do downloader para adiar o carregamento de qualquer pacote externo que pode ser necessário. Além disso, você também tem livre cache recursos para quaisquer recursos dinamicamente baixados. Entre outras coisas, talvez você deseja adicionar um cache local permanente de pacotes que também é capaz de lidar com alterações dinâmicas para a árvore visual. Vamos ver como fazer isso.

Motivação para um cache permanente

Quando se trata O conteúdo dinâmico do Silverlight, há dois aspectos principais através do qual convém obter alguns mais controle.

A primeira é na diretiva de expiração do conteúdo baixado. Você pode deseja controlar exatamente quando um determinado pacote expira e precisa ser baixado novamente. Além disso, convém vincular a expiração de alguns evento externo, como uma ação de determinado usuário ou alterações em outros recursos em cache. Se você souber como funciona o cache ASP.NET, você saberá o que QUERO dizer.

O cache do ASP.NET, na verdade, permite que você armazena dados em cache e fornecer sua própria diretiva de expiração de cada item em cache — com base nas alterações de arquivo, data/hora, ou mesmo alterações nos outros itens em cache. Um mecanismo semelhante não existe no Silverlight 2, mas aplicativos grandes, dinâmicos e altamente personalizáveis obterá benefícios significativos dele.

O segundo aspecto do cache de recursos padrão do Silverlight que você deseja alterar considera a exposição do seus pacotes a atividade do usuário. Em outras palavras, qualquer pacote XAP salvo no cache do navegador é no mercy do usuário. Se o usuário limpar o cache funcionando na interface do navegador, todos os pacotes do XAP serão inevitavelmente perdidos.

Um cache permanente gerenciados de aplicativo aborda dois problemas. XAP pacotes armazenados em cache este permanente não poderiam ser afetadas pelo usuário limpando o cache do navegador. Para armazenar o Silverlight XAP pacotes permanentemente, você precisará obter acesso ao sistema de arquivos local. Por motivos de segurança, o Silverlight não permite que aplicativos acessar o sistema de arquivos local inteiro. No entanto, a API do armazenamento isolado é aqui para ajudá-lo. Para obter mais informações sobre a segurança do Silverlight, consulte"Tudo sobre o CLR: segurança no Silverlight 2."

Fundamentos do armazenamento isolado

Armazenamento isolado não foi criado especificamente para o Silverlight. Armazenamento isolado tem sido parte do Microsoft .NET Framework desde a versão 1.0. Armazenamento isolado com o objetivo de aplicativos parcialmente confiáveis, permite que esses aplicativos para armazenar dados no computador local relação completa de qualquer diretiva de segurança em andamento. Um clássico totalmente confiáveis aplicativo .NET provavelmente possui não precise nunca percorrer a camada de armazenamento isolado para salvar dados de seus próprio, mas para um aplicativo parcialmente confiável, armazenamento isolado é a única opção para salvar dados no cliente.

Da perspectiva do Silverlight, armazenamento isolado é uma ferramenta poderosa e a maneira só é possível para manter partes relativamente grandes de dados de maneira de vários navegadores e sem qualquer um das restrições que afetam, por exemplo, cookies HTTP. É importante entender este ponto: No Silverlight, armazenamento isolado é a possibilidade de apenas você têm a dados de cache na máquina local. Se um aplicativo de Silverlight precisa salvar alguns dados — qualquer tipo de dados — localmente, em seguida, ele só poderá fazer isso por meio de armazenamento isolado. Além disso, com armazenamento isolado cada aplicativo pode manter seus próprios dados isolados de outros aplicativos ou de outros aplicativos fora do site.

Se você deseja uma introdução geral, orientado a .NET a armazenamento isolado e seus cenários de uso mais comuns, você deve ler aGuia do desenvolvedor de .NET framework para o armazenamento isolado. O artigo menciona alguns cenários em que usar o armazenamento isolado não é apropriado. Em particular, as diretrizes de dizer que você deve não estar usando armazenamento isolado para armazenar configurações confidenciais de dados, código ou configuração (diferente de preferências do usuário). Essas diretrizes se originam de um reconhecimento gerais de segurança e não implicam, necessariamente, os riscos inerentes ao uso de armazenamento isolado.

Portanto, pode com segurança armazenados em pacotes XAP que você baixar no armazenamento isolado do Silverlight? No Silverlight, ao contrário no CLR da área de trabalho, qualquer parte do código executável não é confiável por padrão e não é permitido para chamar métodos importantes ou elevar os privilégios da pilha de chamada. No Silverlight, qualquer código que você armazenar para execução posterior será não é possível fazer algo perigoso. Isso é não mais arriscado do que qualquer outra parte do Silverlight código em execução. Criando um cache permanente de pacotes do Silverlight, você acaba localmente armazenando um segmento do aplicativo Silverlight consciously que está executando.

No Silverlight, a função do armazenamento isolado é análoga — que diz respeito a persistência — à função de cookies HTTP em aplicativos da Web clássicos. No Silverlight, você deve procurar no armazenamento isolado como um conjunto de cookies maiores que pode conter qualquer tipo de dados, incluindo o código executável. Nesse caso, entretanto, o núcleo do Silverlight CLR fornece proteção. Conforme ao modelo de segurança Silverlight, na verdade, o núcleo CLR lançará uma exceção sempre que o código do aplicativo quer executar métodos importantes. Ao contrário de cookies HTTP, armazenamento isolado no Silverlight não está vinculado a E/s de rede e nenhum conteúdo é transmitido com solicitações.

Dados no armazenamento isolado são isolados por aplicativo e nenhum outro aplicativo do Silverlight pode acessar o armazenamento. Os dados são armazenados no sistema de arquivos local, no entanto, portanto, um administrador da máquina é certamente capaz de acessá-lo.

Novamente, o modelo geral não é muito diferente do que acontece com cookies HTTP. Um administrador pode sempre localizar e até mesmo alterar o conteúdo dos cookies. Se vale a pena em seu contexto, você pode usar criptografia para adicionar outro nível de proteção de dados.

Se você estiver ainda preocupados com ter algum código executável baixado residente em torno de seu computador, você deve atualizar sua compreensão do modelo de segurança o Silverlight do. Em resumo, o núcleo do Silverlight CLR lança uma exceção que qualquer código de aplicativo de tempo tenta executar um método crítico. No Silverlight classe biblioteca BCL (Base), métodos e classes que executam operações exigindo privilégios altos são marcados com um atributo SecurityCritical especial. Observe que esse é o caso com maior parte do conteúdo do namespace System.IO.

A segurança do Silverlight reconhece algumas classes de plataforma talvez precise fazer seguras chamadas para métodos importantes. Essas classes e métodos, em seguida, são marcados com o atributo SecuritySafeCritical. Esse é o caso com classes na API System.IO.IsolatedStorage (veja a Figura 1 ). O ponto-chave sobre a segurança do Silverlight é que nenhuma parte do código do aplicativo já pode ser marcada com o atributo SecurityCritical ou SecuritySafeCritical. Esse atributo é reservado para classes no assemblies assinados digitalmente pela Microsoft e carregada na memória do diretório de instalação do Silverlight.

fig01.gif

Figura 1 localização dentro o API do armazenamento isolado

Como você pode ver, mesmo em circunstâncias muito infeliz (e provavelmente não) que alguns rapaz mal-intencionado penetrates seu computador e substitui baixado O conteúdo do Silverlight, o dano é limitado a operações normais executáveis em modo transparente.

API do armazenamento isolado

O Silverlight BCL vem com sua própria implementação do armazenamento isolado que seja feito sob medida para o cenário da Web. Armazenamento isolado fornece acesso a uma subárvore do sistema de arquivos todo local, e nenhum método ou propriedade permite sempre que executar o código para descobrir onde o armazenamento de arquivo estiver localizado fisicamente na máquina do usuário. Um aplicativo Silverlight não é permitido usar caminhos de sistema de arquivo absoluto por meio de armazenamento isolado. Da mesma forma, informações sobre a unidade não está disponível e não há suporte para o e o mesmo aplica a caminhos relativos que contêm reticências como este:

\..\..\myfile.txt 

A subárvore de armazenamento isolado é raiz em uma pasta localizada no caminho do usuário atual. Por exemplo, no Windows Vista, a raiz da pasta armazenamento isolado está localizada no diretório de usuários.

Um aplicativo de Silverlight obtém acesso ao ponto de entrada do armazenamento isolado específicas do aplicativo por meio de uma chamada de método:

using (IsolatedStorageFile iso = 
       IsolatedStorageFile.GetUserStoreForApplication()) 
{
  ...
}

O método estático que GetUserStoreForApplication retorna o símbolo você usa para qualquer acesso adicional ao armazenamento isolado. Quando a primeira chamada para GetUserStoreForApplication é feita, a subárvore específicas do aplicativo será criada, se ele já não existir.

O armazenamento isolado do Silverlight API fornece classes para trabalhar com arquivos e diretórios dentro da subárvore do sistema de arquivos protegidos. Felizmente, a lista de classes que você precisa saber é relativamente curta; você poderá encontrá-los na Figura 2 .

fig02.gif

Na classe IsolatedStorageFile, há um número de métodos para criar e excluir arquivos e diretórios, para verificar a presença de arquivos e diretórios e possa ler e gravar novos arquivos (em inglês). Você empregar fluxos para trabalhar com arquivos. Opcionalmente, você poderá dispor up fluxos com leitores de fluxo, que são objetos muito mais à vontade para trabalhar com. a Figura 3 mostra um exemplo breve de como criar um arquivo de armazenamento isolado usando um gravador de fluxo.

A Figura 3 Criando um arquivo de armazenamento isolado

using (IsolatedStorageFile iso = 
      IsolatedStorageFile.GetUserStoreForApplication())
{
    // Open or create the low level stream
    IsolatedStorageFileStream fileStream;
    fileStream = new IsolatedStorageFileStream(fileName, 
        FileMode.OpenOrCreate, iso);

    // Encapsulate the raw stream in a more convenient writer
    StreamWriter writer = new StreamWriter(stream);

    // Write some data
    writer.Write(DateTime.Now.ToString());

    // Clean up
    writer.Close();
    stream.Close();
}

Depois que você dispor de um fluxo de nível inferior em um gravador de fluxo mais conveniente ou leitor, o código que você usa para escrever (ou ler) alguns dados é praticamente idêntico ao código que você deseja usar em um aplicativo .NET clássico. Vamos ver como aproveitar o armazenamento isolado API para salvar qualquer pacote XAP baixado localmente e recarregá-lo posteriormente.

Criar um cache permanente de pacotes

Na coluna do mês passado, eu usei uma classe de invólucro downloader para ocultar alguns do código clichê que é necessário baixar um pacote XAP e extrair módulos (assemblies) e outros recursos. A classe Downloader, no entanto, não é apenas uma classe auxiliar. Conceitualmente, ele representa uma peça não trivial de lógica que talvez queira isolar do restante do código do aplicativo por uma série de razões.

O primeiro motivo que springs à mente é testability. Ao expor a funcionalidade de um componente do downloader por meio de uma interface, você obtém a possibilidade de forma rápida e eficiente a simulação a downloader para fins de teste. Além disso, representa uma interface a ferramenta você pode utilizar para substituir um downloader mais simples uma mais sofisticados um que, talvez, apenas ocorre para oferecer suporte a cache de pacote. a Figura 4 mostra a arquitetura do projeto que deve ser visam para.

fig04.gif

A Figura 4 O componente do Downloader e o REST do aplicativo

fig05.gif

A Figura 5 extraindo uma interface

No código-fonte do mês passado, a classe Downloader era uma parte monolítico do código. Para um design mais flexível, vamos extraia uma interface dele. Como mostra a Figura 5 , o Visual Studio tem um menu de contexto que, embora não tão rich do comerciais ferramentas de refatoração, oferece ajuda com a extração de uma interface fora de uma classe.

Agora que o núcleo do seu aplicativo Silverlight fala para a interface IDownloader, toda a lógica para o pacote do armazenamento em cache deve passar apenas dentro a classe downloader real:

interface IDownloader
{
    void LoadPackage(string xapUrl, string asm, string cls);
    event EventHandler<Samples.XapEventArgs> XapDownloaded;
}

Em particular, o método LoadPackage irá ser reescrito para incorporar a lógica que pode verificar a existência do pacote XAP especificado no armazenamento isolado e baixe-da Internet caso contrário. a Figura 6 mostra uma seção grande parte do código para a classe Downloader. O método primeiro tenta obter o fluxo de pacote XAP do cache interno. Se essa tentativa falhar, o método continua e baixará o pacote do servidor host. (Isso é apenas o que eu discutidos detalhadamente no mês passado.)

Suporte de cache a Figura 6 para o componente Downloader

public void LoadPackage(string xap, string asm, string cls)
{
    // Cache data within the class
    Initialize(xap, asm, cls, PackageContent.ClassFromAssembly);

    // Have a look in the cache
    Stream xapStream = LookupCacheForPackage();
    if (xapStream == null)
        StartDownload();
    else
    {
        // Process and extract resources
        FindClassFromAssembly(xapStream);
    }
}

protected Stream LookupCacheForPackage()
{
    // Look up the XAP package for the assembly.
    // Assuming the XAP URL is a file name with no HTTP information
    string xapFile = m_data.XapName;

    return DownloadCache.Load(xapFile);
}

protected void StartDownload()
{
    Uri address = new Uri(m_data.XapName, UriKind.RelativeOrAbsolute);
    WebClient client = new WebClient();

    switch (m_data.ActionRequired)
    {
        case PackageContent.ClassFromAssembly:
            client.OpenReadCompleted += 
                new OpenReadCompletedEventHandler(OnCompleted);
            break;
        default:
            return;
    }
    client.OpenReadAsync(address);
}

private void OnCompleted(object sender, OpenReadCompletedEventArgs e)
{
    // Handler registered at the application level?
    if (XapDownloaded == null)
        return;

    if (e.Error != null)
        return;

    // Save to the cache
    DownloadCache.Add(m_data.XapName, e.Result);

    // Process and extract resources
    FindClassFromAssembly(e.Result);
}

private void FindClassFromAssembly(Stream content)
{
    // Load a particular assembly from XAP
    Assembly a = GetAssemblyFromPackage(m_data.AssemblyName, content);

    // Get an instance of the specified user control class
    object page = a.CreateInstance(m_data.ClassName);

    // Fire the event
    XapEventArgs args = new XapEventArgs();
    args.DownloadedContent = page as UserControl;
    XapDownloaded(this, args);
}

No Silverlight, download é um processo assíncrono, portanto, o método interno StartDownload dispara um evento de "concluído" quando o pacote está totalmente disponível no cliente. O manipulador de eventos primeiro salva o conteúdo de fluxo de pacote XAP em um arquivo local e, em seguida, extrai recursos dele. Observe que no código de exemplo estou extrair os assemblies só; em um componente mais geral que você deseja estender cache recursos para qualquer outro tipo de recurso, como o XAML para animações, imagens ou outros arquivos auxiliares.

O método LoadPackage na classe Downloader é usado para baixar Silverlight­user controles para inserir na árvore de XAML atual. Como o pacote XAP é um recipiente multiarquivos, você precisará especificar qual assembly contém o controle de usuário e o nome de classe. O código na Figura 6 simplesmente extrai o conjunto especificado do pacote, carrega o AppDomain atual e, em seguida, cria uma instância da classe especificada contida.

E se o assembly tem algumas dependências? O código na Figura 6 simplesmente não cobre neste cenário. Como resultado, se o assembly passado como um argumento para LoadPackage tem uma dependência em outro assembly (mesmo no mesmo pacote XAP), você obterá uma exceção assim que o fluxo de execução atinge uma classe no assembly de dependência. O ponto é que todos os assemblies no pacote devem ser carregados na memória. Para que isso acontecer, que você precisa acessar o arquivo de manifesto, leia sobre assemblies implantados e processá-los. a Figura 7 mostra como carregar na memória todos os assemblies referenciados no arquivo de manifesto.

A Figura 7 carregar todos os assemblies no manifesto

private Assembly GetAssemblyFromPackage(
     string assemblyName, Stream xapStream)
{
    // Local variables
    StreamResourceInfo resPackage = null;
    StreamResourceInfo resAssembly = null;

    // Initialize
    Uri assemblyUri = new Uri(assemblyName, UriKind.Relative);
    resPackage = new StreamResourceInfo(xapStream, null);
    resAssembly = Application.GetResourceStream(
                              resPackage, assemblyUri);

    // Extract the primary assembly and load into the AppDomain 
    AssemblyPart part = new AssemblyPart();
    Assembly a = part.Load(resAssembly.Stream);

    // Load other assemblies (dependencies) from manifest
    Uri manifestUri = new Uri("AppManifest.xaml", UriKind.Relative);
    Stream manifestStream = Application.GetResourceStream(
        resPackage, manifestUri).Stream; 
    string manifest = new StreamReader(manifestStream).ReadToEnd();

    // Parse the manifest to get the list of referenced assemblies
    List<AssemblyPart> parts = ManifestHelper.GetDeploymentParts(manifest);

    foreach (AssemblyPart ap in parts)  
    {
        // Skip over primary assembly (already processed) 
        if (!ap.Source.ToLower().Equals(assemblyName))
        {
            StreamResourceInfo sri = null;
            sri = Application.GetResourceStream(
                resPackage, new Uri(ap.Source, UriKind.Relative));
            ap.Load(sri.Stream);
        }
    }

    // Close stream and returns
    xapStream.Close();
    return a;
}

O arquivo de manifesto é um arquivo XML, conforme mostrado aqui:

<Deployment EntryPointAssembly="More" EntryPointType="More.App" 
            RuntimeVersion="2.0.31005.0">
  <Deployment.Parts>
    <AssemblyPart x:Name="More" Source="More.dll" />
    <AssemblyPart x:Name="TestLib" Source="TestLib.dll" />
  </Deployment.Parts>
</Deployment> 

Para analisar este arquivo, você pode usar LINQ-to-XML. O código-fonte contém uma classe de ManifestHelper exemplo com um método que retorna uma lista de objetos AssemblyPart (consulte a Figura 8 ). Vale a pena observar que em versões beta do Silverlight 2, você pode usar a classe XamlReader para analisar o arquivo de manifesto para um objeto de implantação:

// This code throws in Silverlight 2 RTM
Deployment deploy = XamlReader.Load(manifest) as Deployment;

A Figura 8 análise o manifesto usando LINQ-to-XML

public class ManifestHelper
{
   public static List<AssemblyPart> GetDeploymentParts(string manifest)
   {
      XElement deploymentRoot = XDocument.Parse(manifest).Root;
      List<AssemblyPart> parts = 
          (from n in deploymentRoot.Descendants().Elements() 
           select new AssemblyPart() { 
                Source = n.Attribute("Source").Value }
          ).ToList();

          return parts;
   }
}

Na versão de lançamento, o objeto de implantação tenha sido transformado em um singleton e subseqüentemente não pode ser usado para carregar assemblies dinamicamente. O XML no manifesto, portanto, deve ser analisado manualmente.

Diretivas de expiração

Conforme implementado até o momento, o cache de assemblies é permanente e não há uma maneira para que o usuário obter pacotes atualizados. A solução só é possível é ter um administrador da máquina localizar arquivos de armazenamento isolado para o aplicativo e excluí-los manualmente por meio do Windows Explorer.

Vamos ver o que levaria para adicionar uma diretiva de expiração simples que faz qualquer arquivo XAP em cache obsoleto após um determinado período de tempo após o download. O local correto para definir uma diretiva de expiração é a classe DownloadCache, como na Figura 6 . Quando você adiciona um arquivo XAP ao cache, você precisa armazenar algumas informações sobre o tempo de download. Quando você acessa o cache para pegar um pacote, você deve verificar se o pacote está vencido (veja a Figura 9 ).

A Figura 9 Test para expiração de

public bool IsExpired(string xapFile)
{
    bool expired = true;
    if (m_ItemsIndex.ContainsKey(xapFile))
    {
        DateTime dt = (DateTime)m_ItemsIndex[xapFile];

        // Expires after 1 hour
        expired = dt.AddSeconds(3600) < DateTime.Now;    
        if (expired)
            Remove(xapFile);
    }

    return expired;
}

A implementação de um algoritmo aparentemente simples é prejudicada por um fatos importantes. No Silverlight, você não tem como atributos de arquivo de acesso como última vez de atualização ou criação. Isso significa que são responsáveis pelo gerenciamento de informações de tempo. Em outras palavras, quando você adiciona um XAP ao cache também criar uma entrada em alguns dicionário personalizado e persistente que controla quando o pacote foi baixado. Não é necessário dizer que essa informação deve ser mantido no alguma forma para o armazenamento isolado. a Figura 10 ilustra esse conceito.

A Figura 10 Persisting download detalhes para o armazenamento isolado

public static Stream Load(string file)
{
    IsolatedStorageFile iso;
    iso = IsolatedStorageFile.GetUserStoreForApplication();

    if (!iso.FileExists(file))
    {
        iso.Dispose();
        return null;
    }

    // Check some expiration policy
    CacheIndex m_Index = new CacheIndex();
    if (!m_Index.IsExpired(file))
        return iso.OpenFile(file, FileMode.Open);

    // Force reload
    iso.Dispose();
    return null;
}

CacheIndex é uma classe do auxiliar que usa as configurações de aplicativo nativo do Silverlight API para manter um dicionário de nomes XAP e baixar horas para o armazenamento isolado. O membro m_ItemIndex é um objeto Dictionary simples instanciado no construtor de CacheIndex, como mostrado na Figura 11 .

Figura 11 A classe CacheIndex

public class CacheIndex
{
    private const string XAPCACHENAME = "XapCache";
    private Dictionary<string, object> m_ItemsIndex; 
    public CacheIndex()
    {
      IsolatedStorageSettings iss;
      iss = IsolatedStorageSettings.ApplicationSettings;
      if (iss.Contains(XAPCACHENAME))
         m_ItemsIndex = iss[XAPCACHENAME] as Dictionary<string, object>;
      else
      {
         m_ItemsIndex = new Dictionary<string, object>();
         iss[XAPCACHENAME] = m_ItemsIndex;
         iss.Save();
      }
   }
  ...
}

ApplicationSettings é um recurso muito bom de 2 do Silverlight. Ele basicamente consiste em um dicionário de seqüência/objeto e é lidos automaticamente do armazenamento no aplicativo ao carregar e salvo o armazenamento no desligamento. Qualquer objeto (serializável) que você adicionar ao dicionário é mantido automaticamente.

Criando uma entrada XAPCACHENAME no dicionário, você organizar manter o conteúdo do dicionário de XAP. O dicionário XAP contém uma entrada para cada pacote baixado combinado com o tempo de download, como você ver na Figura 12 . Observe que a API de ApplicationSettings também oferece um método de salvar para forçar a persistência antes de desligamento do aplicativo.

Informações sobre a Figura 12 adicionando o download

public void Add(string xapFile)
{
    m_ItemsIndex[xapFile] = DateTime.Now;
    IsolatedStorageSettings iss;
    iss = IsolatedStorageSettings.ApplicationSettings;
    iss.Save();                
}

public void Remove(string xapFile)
{
    m_ItemsIndex.Remove(xapFile);
    IsolatedStorageSettings iss;
    iss = IsolatedStorageSettings.ApplicationSettings;
    iss.Save();
}

Juntando tudo

Todos os a alterações e detalhes discutidos até o momento ocorrem atrás das cortinas de uma classe pública — a classe Downloader. Ao incorporar essa classe em seu aplicativo do Silverlight, você obtém vários níveis de cache em uma única captura. Com codificação apropriada que você pode armazenar em cache baixados controles de usuário para a duração da sessão do aplicativo. Se você baixar conteúdo que vai para, digamos, um item de guia, você pode, em seguida, Ocultar e Mostrar o item de guia repetidamente sem a necessidade de baixar o pacote repetidas.

Se você baixar através da classe WebClient (como na coluna do último mês), você passar o mecanismo de navegador e obter o cache de nível de navegador. Qualquer pacote XAP baixado reside na máquina do usuário até que o usuário limpar o cache do navegador. Finalmente, a classe de Downloader que você obtém com esta coluna oferece suporte a um cache permanente por meio de armazenamento isolado. Isso significa que sempre que você baixar via WebClient, o pacote XAP também é salvas para o armazenamento local.

A classe Downloader, no entanto, também oferece pegar o arquivo de armazenamento XAP se um pacote válido pode ser encontrado. Observe que isso funciona em sessões do aplicativo. Baixe o pacote de uma vez, você trabalha e, em seguida, desligue o aplicativo. Quando você continuar, o pacote é recarregado do armazenamento se não tiver expirado. E se o pacote expira? Nesse caso, o downloader passe WebClient. Mas nesse momento, WebClient apenas pode retornar uma cópia anteriormente em cache do navegador do pacote do mesmo.

Isso é próprio do projeto. Para ignorar o cache de nível de navegador, você precisará desativá-lo na solicitação HTTP original, como discutidas no mês passado. Você deve armazenar em cache propriedades no nível da página ou obter o pacote através de um manipulador HTTP onde é possível definir diretivas de expiração com mais precisão sem afetar outros recursos que acompanham a página.

Algumas anotações final

Armazenamento em cache o pacote XAP não significa que o cache de recursos individuais, como DLLs, animações em XAML, ou conteúdo multimídia. Na implementação atual, recursos são extraídos do pacote XAP sempre que eles são usados. No entanto, este é um aspecto que é mais possível melhorar com a classe Downloader. Da mesma forma, o pacote oferece um controle de usuário, mas não controla as alterações que o usuário pode forçar em sua interface do usuário. Controle de alterações dinâmicas à árvore de XAML é outro tópico e merece um artigo de seu próprio.

Há duas maneiras para acessar um sistema de arquivo particular do Silverlight na máquina do usuário local. Em todos os os trechos de código para esta coluna, usei o método GetUserStoreForApplication na classe IsolatedStorageFile. Esse método retorna um token de acesso uma seção do sistema de arquivos que é isolado por aplicativo, que significa que todos os e somente os assemblies associados a um aplicativo usar o mesmo armazenamento. Você também pode selecionar um armazenamento e compartilhá-lo em todos os aplicativos hospedados no mesmo site. Nesse caso, você obter o token por meio do método GetUserStoreForSite.

Observe também que armazenamento local pode ser administrado através a caixa de diálogo de configuração do Silverlight (clique com o botão direito do mouse em um aplicativo do Silverlight) e mesmo desativado completamente. Nesse caso, ao tentar obter o token, uma exceção ser gerada. Uma cota de disco também se aplica para o armazenamento local em uma base por domínio; seu valor padrão é 1 MB. Lembre-se isso ' durante o planejamento para um cache Silverlight permanente.

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

Dino Esposito é um arquiteto na arquitetura na IDesign e o co-autor de Microsoft .NET: Architecting Applications for the Enterprise (Microsoft Press, 2008). Residente na Itália, Dino é palestrante assíduo em eventos do setor no mundo inteiro. Você pode ingressar em seu blog em weblogs.asp. NET/despos.