Compartilhar via


O modelo de endereçamento das Convenções de Empacotamento Aberto

 

David Meltzer e Andrey Shur
Microsoft Corporation

Junho de 2006

Aplica-se a:
   Open Packaging Conventions
   Microsoft Office 2007
   Microsoft Windows Vista
   Microsoft .NET Framework

Resumo: Este artigo fornece uma visão geral do modelo de endereçamento usado nas Convenções de Empacotamento Aberto, incluindo como os pacotes e suas partes são abordados, como as referências relativas nas partes do pacote são resolvidas e como os aplicativos podem usar o modelo de endereçamento de pacote com a ajuda dos .NET Framework e classes. (16 páginas impressas)

Sumário

Prefácio
O modelo de endereçamento
Suporte de programação para URIs "pack:"
Referências

Prefácio

Como parte do design do Office 2007 e do Windows Vista, a Microsoft introduziu as Convenções de Empacotamento Aberto. Essas convenções descrevem como o conteúdo pode ser organizado em um "pacote". Alguns exemplos de conteúdo incluem um documento, uma coleção de mídias e uma biblioteca de aplicativos. Os pacotes agregam todos os componentes do conteúdo em um único objeto.

Um aplicativo de processamento de palavras pode usar pacotes, por exemplo, para armazenar as páginas de um documento, as fontes necessárias e as imagens, gráficos e anotações nas páginas. Um aplicativo de exibição ou gerenciamento de documentos pode exibir apenas partes do conteúdo em um pacote. Os aplicativos podem usar um formato baseado em pacote, como a XPS (Especificação de Papel XML), para enviar conteúdo e recursos de layout fixo para uma impressora.

Este artigo fornece uma visão geral do modelo de endereçamento usado nas Convenções de Empacotamento Aberto, incluindo como os pacotes e suas partes são abordados e como as referências relativas nas partes do pacote são resolvidas. Este artigo também discute como os aplicativos podem usar o modelo de endereçamento de pacote com a ajuda das classes .NET Framework e .NET Framework 3.0. Este artigo é escrito principalmente para desenvolvedores de aplicativos que manipularão, produzirão ou consumirão pacotes.

Para obter informações normativas completas necessárias para implementar o modelo de endereçamento de pacote, consulte a especificação das Convenções de Empacotamento Aberto. Os SDKs do .NET Framework 3.0 e do .NET fornecem mais informações sobre as classes e os métodos discutidos.

O material apresentado nesta visão geral pressupõe um conhecimento básico da especificação de URI. Os termos a seguir são usados de acordo com RFC 3986: URI, referência de URI, componente de esquema, componente de autoridade, componente de caminho, caminho absoluto e referência relativa. O termo URI sempre indica a forma absoluta de um URI – o componente de esquema está presente e todos os outros componentes correspondem à gramática específica do esquema. O termo endereçável, conforme usado aqui, indica que existe um URI que identifica um recurso.

O modelo de endereçamento

As Convenções de Empacotamento Aberto definem um modelo lógico para organizar o conteúdo e os recursos de um pacote e fornecem um mapeamento desse modelo lógico para uma representação física, com base em ZIP, XML e outras tecnologias abertamente disponíveis.

O modelo de empacotamento lógico descrito pelas Convenções de Empacotamento Aberto define uma abstração de pacote que contém uma coleção de partes. As partes podem ter relações entre si e o pacote pode ter relações com partes. O modelo de empacotamento especifica como as partes em um pacote são nomeadas, referenciadas e relacionadas. O modelo de endereçamento definido pelas Convenções é a base para poder referenciar e obter recursos de parte em um pacote.

Recursos de pacote endereçáveis

Uma instância de pacote como um todo é um recurso endereçável, assim como cada parte mantida na instância do pacote.

Endereçando um pacote como uma unidade

Os aplicativos podem usar um URI com qualquer esquema (por exemplo, "http:", "ftp:" e assim por diante) para abordar um pacote como uma unidade, adquirindo o fluxo de bits que compõem todo o pacote.

Os aplicativos também podem abordar um pacote usando o esquema de URI "pack:" definido pelas Convenções de Empacotamento Aberto. Esse esquema especifica que o URI completo que identifica o pacote é mantido no componente de autoridade de um URI "pack:" em um formulário codificado.

Exemplo: endereçando um pacote

O recurso de pacote é endereçado por URIs "http:" e "pack:" (respectivamente) nos seguintes exemplos:

http://www.site.com/windows/p1.xps

pack://http%3a,,www.site.com,windows,p1.xps/

O tipo MIME do recurso de pacote adquirido indica o formato de arquivo do pacote, por exemplo, pode ser formato de documento XPS (.xps), formato Office Open XML (.docx) ou algum outro formato que esteja em conformidade com as Convenções de Empacotamento Aberto.

Por vários motivos (como melhorar o desempenho), os aplicativos podem usar um URI específico para seu domínio como o componente de autoridade de um URI "pack:". Esse URI só pode ser resolvido no contexto de um determinado aplicativo. A técnica de programação usada para esses URIs específicos do aplicativo é descrita posteriormente, em "The PackageStore".

Endereçando partes dentro de um pacote

As partes em um pacote são endereçadas usando URIs "pack:". A estrutura de um URI "pack:" que trata de uma parte é a seguinte: caminho de pack://< authority><>

Exemplo: Endereçando partes

pack://http%3a,,www.site.com,windows,p1.xps/fonts/arial.ttf aborda a parte chamada /fonts/arial.ttf, no pacote endereçado por http://www.site.com/windows/p1.xps.

O componente de autoridade contém o URI codificado de todo o pacote; o componente path contém o nome da parte nesse pacote. Os nomes de parte estão em conformidade com a gramática definida para o componente de URI path-absolute ([2], seção 3.3), com algumas restrições adicionais ([1], seção 2.1.1.1).

Exemplo: nomes de parte

/documents/doc1.xaml

/pages/page4.xaml

/fonts/arial.ttf

Nomes de partes não diferenciam maiúsculas de minúsculas cadeias de caracteres ASCII. Todas as partes em um pacote têm nomes exclusivos.

Usando identificadores de fragmento para fazer referência a partes

Alguns aplicativos que usam as Convenções de Empacotamento Aberto podem referenciar uma parte usando um URI não"pack:" de uma unidade de pacote com identificadores de fragmento específicos de formato.

Exemplo: usando um URI não"pack:" para referenciar uma parte

O URI http://www.site.com/windows/p1.xps\#15 é usado para fazer referência à parte que representa a página 15 no documento p1.xps ([3], seções 9.2.2 e 9.2.3).

Embora seja válido e, para determinados cenários, útil ter URIs não"pack:" referem-se a partes, esses URIs não podem ser usados como URIs base para resolve referências relativas no conteúdo da parte.

Referindo-se a entradas em partes

Uma parte é o recurso endereçável mais granular dentro de um pacote. No entanto, os aplicativos podem precisar se referir a entradas dentro do conteúdo de uma parte. Para determinados tipos de conteúdo, as entradas podem ser referenciadas por meio de identificadores de fragmento ([2], seção 3.5). As Convenções de Empacotamento Aberto não especificam identificadores de fragmento. Os aplicativos que usam identificadores de fragmento são responsáveis por processá-los corretamente.

Exemplo: referenciando entradas em partes

pack://http%3a,,www.site.com,windows,p1.xps/pages/page1.xaml#//[@Id="A012"] refere-se a um conjunto de nós XML dentro do conteúdo da parte chamada /pages/page1.xaml e tem o valor do atributo Id de A012.

Pacotes aninhados

Os pacotes podem ser aninhados. Uma parte em um pacote pode conter conteúdo de qualquer tipo, incluindo um pacote inteiro. As partes de um pacote aninhado podem ser abordadas por um URI "pack:", com um componente de autoridade que indica a parte que contém esse pacote aninhado ([1], Apêndice D.3).

Exemplo: Endereçando partes em pacotes aninhados

Um pacote localizado em http://www.site.com/package contém uma parte chamada /nested-package

,

endereçado pelo pacote de URI "pack:" ://http%3a,,www.site.com,package/nested-package.

A parte endereçada pelo URI anterior contém uma unidade de pacote, que contém uma parte chamada /p1.xaml.

O endereço dessa parte no pacote aninhado é o seguinte:

pack://pack%3a,,http:%253a%2c%2cwww.site.com%2cpackage,nested-package/p1.xaml.

Referências no conteúdo da parte

Partes com determinados tipos de conteúdo, como XML, podem conter referências de URI. As referências de URI podem ser URIs ou referências relativas. As referências de URI podem ser representadas no conteúdo por cadeias de caracteres Unicode. Os aplicativos que resolvem essas referências de URI devem converter as cadeias de caracteres em um formulário de URI ([4], seção 3.1).

Uma referência relativa é um URI expresso em relação ao URI base do conteúdo que contém a referência. O URI base padrão para o conteúdo da parte é o URI "pack:" que trata da parte.

Exemplo: URI base

O URI base de uma parte chamada /pages/page1.xaml em um pacote endereçado por http://www.site.com/windows/p1.xps é o seguinte:

pack://http%3a,,www.site.com,windows,p1.xps/pages/page1.xaml.

Se um URI de base alternativo for necessário para resolve referências relativas nas entradas do conteúdo da parte, um aplicativo deverá especificar explicitamente o alternativo. Tipos de conteúdo específicos expõem determinadas maneiras de especificar o URI de base alternativo. Por exemplo, XML usa o atributo xml:base , HTML usa o <elemento base> e As Convenções de Empacotamento Aberto usam o atributo TargetMode para elementos Relationship .

Usar o URI "pack:" de uma parte como o URI base para uma referência relativa garante que o recurso referenciado fará parte do mesmo pacote ([2], seção 5.2), a menos que a referência relativa esteja no formato de caminho de rede raramente usado (ou seja, uma referência relativa começando com "//").

Exemplo: resolvendo uma referência relativa

A referência relativa .. /.. /page2.xaml na parte endereçada como pack://http%3a,,www.site.com,windows,p1.xps/pages/page1.xaml foi resolvida para pack://http%3a,,www.site.com,windows,p1.xps/page2.xaml, abordando a parte chamada /page2.xaml.

Os produtores de pacotes podem usar nomes de parte como uma forma válida de referências relativas. No entanto, ao usar nomes de parte como referências relativas, os produtores devem considerar se as partes referenciadas também podem ser tratadas como recursos extraídos fora do pacote. Depois que as partes forem extraídas de um pacote, os nomes de parte usados como referências relativas poderão não ser resolvidos conforme o esperado. A barra à esquerda obrigatória para nomes de parte, especificada pela gramática de nome de parte, implica que essas referências relativas são resolvidas da raiz da autoridade atual.

Exemplo: Endereçando recursos extraídos

No conteúdo de uma parte chamada /doc1/pages/page1.xaml, a referência relativa /page2.xaml trata da parte chamada /page2.xaml e a referência relativa ./page3.xaml trata da parte chamada /doc1/pages/page3.xaml.

Depois que as partes /doc1/pages/page1.xaml, /doc1/pages/page3.xaml e /part2.xaml são extraídas do pacote para arquivos chamados file:///c:/mydocs/doc1/pages/page1.xaml, file:///c:/mydocs/doc1/pages/page3.xaml e file:///c:/mydocs/page2.xaml (respectivamente), a referência relativa ./page3.xaml aborda o arquivo file:///c:/mydocs/doc1/pages/page3.xaml, o que é esperado; no entanto, a referência relativa /page2.xaml agora trata do arquivo chamado file:///page2.xaml.

Referências relativas em relações

As Convenções de Empacotamento Aberto definem conexões entre partes de origem e de destino em um pacote como relações ([1], seção 1.3).

As relações são agrupadas e armazenadas com base em suas fontes. Uma parte de relações contém relações originadas na mesma parte de origem. Cada relação é descrita por um elemento XML dentro do conteúdo dessa parte de relações. A parte relações é associada exclusivamente a essa parte de origem (e vice-versa) usando uma convenção de nomenclatura definida para a parte relações.

O URI base padrão para os URIs especificados em cada elemento Relationship é o URI "pack:" da parte de origem ([1], seção 1.3.5). O atributo TargetMode de um elemento Relationship indica o URI base para a relação especificada.

Exemplo: Elemento Relationship

O elemento na parte de relações que define uma relação de uma parte de origem chamada /pages/page1.xaml para a parte de destino /fonts/arial.ttf dentro do mesmo pacote pode ser semelhante ao seguinte:

<Tipo de relação="https://schemas.microsoft.com/xps/2005/06/restricted-font"

TargetMode="Internal" Id="A123" Target=".. /fonts/arial.ttf"/>

O valor Interno do atributo TargetMode indica que o URI base para o elemento Relationship é o padrão para o conteúdo da parte de relações e o mesmo que o URI "pack:" da parte de origem de relações. No exemplo anterior, o URI base do elemento Relationship é o URI "pack:" da parte /pages/page1.xaml .

As relações também podem direcionar recursos externos em relação ao local do pacote inteiro.

Exemplo: relação com destino externo

Para um pacote localizado em file:///c:/office12/sample.docx, o elemento XML

<Id da relação="rId9"

Type="https://schemas.microsoft.com/office/2006/relationships/image"

Target="Icon.JPG" TargetMode="External"/>

define a relação direcionada ao arquivo file:///c:/office12/icon.jpg.

O valor Externo do atributo TargetMode especifica que a relação deve ter como destino um recurso fora do pacote. Se o atributo Target mantiver uma referência relativa, um URI base será necessário. O URI base para esse elemento de relação deve ser o URI do pacote inteiro.

Delegando referências a relações

Alguns formatos baseados em pacote podem evitar o uso de referências de URI no conteúdo, delegando referências a relações. Essa técnica de delegação baseia-se no uso de valores de ID exclusivos em cada elemento Relationship para mapear referências relativas no conteúdo da parte para relações correspondentes.

Exemplo: mapeando referências relativas no conteúdo da parte para relações

Um pacote localizado em file:///c:/office12/sample.docx tem uma parte chamada /word/document.xml que contém

<a:blip relEmbed="rId6" relLink="" w="0" h="0"/>.

A parte de relações anexada a esta parte contém o elemento

<Id da relação="rId6"

Type="https://schemas.microsoft.com/office/2006/relationships/image"

TargetMode="Internal" Target="media/image1.jpeg"/>.

Isso vincula o elemento à parte chamada /word/media/image1.jpeg.

O benefício dessa abordagem é que um aplicativo pode identificar e manter todas as referências dentro de um pacote, sem examinar o conteúdo nas partes.

No entanto, se as referências forem delegadas a relações, as partes do pacote extraídas para arquivos soltos poderão não funcionar corretamente. Para que os destinos de relação funcionem após a extração, um aplicativo de consumo exigirá conhecimento especial sobre relações, Convenções de Empacotamento Aberto para partes de relação de nomenclatura e a definição de URIs base para arquivos de relação.

Suporte de programação para URIs "pack:"

Os aplicativos que produzem e/ou consomem pacotes funcionarão com endereços de pacote e parte e resolve referências relativas dentro do conteúdo das partes. .NET Framework 3.0, que fornece o conjunto de APIs gerenciadas de última geração fornecidas pela Microsoft, inclui classes que dão suporte ao modelo de endereçamento das Convenções de Empacotamento Aberto. Essas classes permitem que os aplicativos componham e analisem referências e obtenham recursos de pacote. A classe PackUriHelper é usada para facilitar o tratamento de URIs "pack:". A classe PackWebRequest é usada para obter recursos endereçados usando URIs "pack:".

Esta seção ilustra as funções que esses serviços executam na composição, análise e resolução de referências.

Disponibilizando os serviços de pacote

O .NET Framework versão 3.0 (ou superior) deve ser instalado para usar as classes de serviços de empacotamento. As classes podem ser encontradas no namespace System.IO.Packaging .

Antes de usar System.Uri para operações em que os URIs "pack:" estão envolvidos, o esquema de URI "pack:" deve ser registrado para o domínio do aplicativo. A maneira mais fácil de registrar o esquema de URI "pack:" é chamando qualquer método da classe PackUriHelper . O esquema também pode ser registrado, sem chamar a classe auxiliar, usando o método UriParser.Register , conforme mostrado no exemplo a seguir. No entanto, o uso desse método requer permissões de segurança.

Exemplo: registrando o esquema de URI "pack:"

//To register the "pack:" URI scheme without calling PackUriHelper

UriParser.Register(new GenericUriParser
   (GenericUriParserOptions.GenericAuthority),
      "pack", -1);

Obtendo o URI "pack:" de um recurso de destino

Ao consumir um pacote, todo o pacote ou uma parte de cada vez pode ser obtido como um objeto . Em ambos os casos, o método PackUriHelper.Create pode ser usado para criar o URI "pack:" do recurso de pacote ou parte. Esse URI "pack:" é passado para o método PackWebRequest para obter o recurso. PackWebRequest é discutido mais detalhadamente na próxima seção, "Obtendo recursos de pacote usando PackWebRequest".

Um exemplo comum de como as classes PackUriHelper e PackWebRequest podem ser usadas para dar suporte ao consumo de um pacote é detalhado nas etapas a seguir. Se o URI do pacote e o URI da parte forem conhecidos, um aplicativo poderá:

  1. Redigir um URI "pack:" do URI do pacote e parte URI, usando PackUriHelper.
  2. Obtenha um fluxo de bits chamando PackWebRequest.
  3. Carregue o conteúdo da parte e analise para obter referências relativas.
  4. Resolva essas referências relativas no URI base da parte (o URI "pack:" composto na Etapa 1).
  5. Use System.Uri para resolve as referências relativas e use PackWebRequest para obter os recursos indicados.

Criando um URI "pack:" para um pacote desejado

O URI "pack:" do pacote pode ser criado usando o método PackUriHelper.Create .

Exemplo: PackUriHelper.Create

//Given the URI for a package
Uri packageUri = new Uri("http://www.newsdocs.com
               /local/today.container");

//Use the Create method to create a "pack:" URI from a non-"pack:" URI
Uri packUri = PackUriHelper.Create(packageUri);

//The resulting packUri value is
//"pack://http%3a,,www.newsdocs.com,local,today.container/"

O URI "pack:" criado é passado para PackWebRequest para obter o recurso de pacote.

Criando um URI "pack:" para uma parte desejada

O URI "pack:" da parte pode ser criado usando o método PackUriHelper.Create .

Exemplo: PackUriHelper.Create

//Given the URI for package 
Uri packageUri = new Uri("http://www.newsdocs.com
               /local/today.container");

//Given the URI for a part
Uri partUri = new Uri("/sports.xml", UriKind.Relative);

//Use the PackUriHelper.Create method to create a "pack:" URI

Uri packUri = PackUriHelper.Create (packageUri, partUri);

//The resulting packUri value is
//"pack://http%3a,,www.newsdocs.com,local,today.container/sports.xml"

O URI "pack:" criado é passado para PackWebRequest para obter o recurso de parte.

Resolvendo referências relativas

Ao processar o conteúdo de uma parte, podem ser encontradas referências relativas que se referem a outras partes ou recursos. Resolver essas referências é uma primeira etapa na obtenção dos recursos referenciados.

Uma referência relativa no conteúdo de uma parte é resolvida em relação ao URI base de uma parte para o URI "pack:" da parte de destino. O URI "pack:" da parte de destino é passado para PackWebRequest para obter o recurso de parte do pacote. O nome de uma parte de destino, derivado do URI "pack:" da parte de destino, também pode ser usado para obter uma parte de destino, passando o nome da parte para o método Package.GetPart .

Ao resolver referências relativas a partes de destino, há vários caminhos que a resolução pode seguir, dependendo de quais informações estão disponíveis no início e se o pacote está aberto (ou pode ser aberto). Dois desses caminhos são os seguintes:

  • No início:

    1. O URI "pack:" de parte que contém a referência é conhecido.
    2. O pacote não está aberto.
    //Given the "pack:" URI for the part "/files/fixeddoc.xaml"
    //packUri =
    // "pack://http%3a,,www.newsdocs.com,local,today.container
    // /files/fixeddoc.xaml"
    
    //The part "/files/fixeddoc.xaml" contains 
    //the relative reference "../images/1.jpg"
    
    Uri relativeReference = new Uri("../images/1.jpg", 
                      UriKind.Relative);
    
    //Use System.Uri to directly obtain the absolute target URI
    
    Uri targetPackUri = new Uri(packUri, relativeReference);
    
    //The value of the resulting targetPackUri is 
    //"pack://http%3a,,www.newsdocs.com,local,today.container
    // /images/1.jpg"
    
    //Now another PackWebRequest can be made using 
    //this targetPackUri value.
    
  • No início:

    1. O nome da parte que contém a referência é conhecido.
    2. O pacote está aberto.
    //Given "package" as the current instance of the Package class.
    //Given the relative reference = "../../images/1.jpg"
    
    Uri relativeReference = new Uri("../../images/1.jpg", 
                      UriKind.Relative);
    
    //Given the URI of the part that contains the relative reference
    
    Uri partUri = new Uri("/files/fixeddoc.xaml");
    
    //Use PackUriHelper.ResolvePartUri to obtain the resolved part URI 
    //of the target based on the part URI above and the relative 
    //reference in that part
    
    Uri targetPartUri = PackUriHelper.ResolvePartUri
                   (partUri, relativeReference);
    
    //The resulting targetPartUri value is "fixeddoc.xaml"
    //Now use the package.GetPart method to obtain the target part
    
    PackagePart packagePart = package.GetPart(targetPartUri);
    

Fornecendo nomes de parte para a classe de pacote

Depois que um pacote é aberto, a classe Package é útil para adicionar partes a pacotes, obter partes e excluir partes. Métodos da classe Package , como Package.AddPart, Package.DeletePart e Package.GetPart, assumem um URI de parte como um parâmetro. O método PackUriHelper.CreatePartUri pode ser usado para criar um nome de parte válido de uma referência relativa ao URI base do pacote.

Exemplo: PackUriHelper.CreatePartUri

//Given a URI

Uri partUri = PackUriHelper.CreatePartUri 
            (new Uri "files/a.xaml",UriKind.Relative))

//The URI will be checked for validity, and a leading slash
//will be added. The resulting partUri value is "/files/a.xaml"

Serviço para gerar referências relativas

Um aplicativo de criação pode precisar derivar uma referência relativa que, quando colocada no conteúdo de uma parte de origem, aponta para uma parte de destino. O método GetRelativeUri atende a essa finalidade.

Exemplo: Exemplo de GetRelativeUri

//Given the URI of the source part

Uri sourcePartUri = new Uri("/tiles/pages/a.xaml", UriKind.Relative);

//Given the URI of the target part

Uri targetPartUri = new Uri("/images/event1/1.jpg", UriKind.Relative);

//Use PackUriHelper.GetRelativeUri to generate the relative reference
//that will be placed in the content of the source part.

Uri relativeReference = PackUriHelper.GetRelativeUri
               (sourcePartUri, targetPartUri);

//The resulting relativeReference value is "../../images/event1/1.jpg"

Obtendo recursos de pacote usando PackWebRequest

Os aplicativos podem obter pacotes e recursos de partes usando PackWebRequest, uma classe derivada de System.Net.WebRequest. PackWebRequest retorna um recurso endereçado por um determinado URI "pack:".

Em geral, iniciar um PackWebRequest para um URI "pack:" consiste nas seguintes etapas:

  1. A gramática de URI "pack:" está marcada.
  2. O componente de autoridade é extraído do URI "pack:" e verificado para ver se ele segue a gramática para um URI absoluto.
  3. Se o componente de caminho do URI "pack:" estiver vazio:
  • O fluxo de pacote é obtido para o componente de autoridade e retornado ao chamador.

    Caso contrário, se o componente de caminho não estiver vazio:

    1. O pacote aberto é obtido para o recurso identificado pelo componente de autoridade. Dependendo do conjunto CachePolicy , PackWebRequest obtém um pacote aberto do PackageStore ou cria uma WebRequest interna para o recurso de pacote e abre o pacote do fluxo de pacote retornado.
    2. A parte é obtida usando o componente path do URI "pack:" como o nome da parte.
    3. O fluxo de parte é obtido e retornado ao chamador.

PackWebResponse.GetStream retorna um fluxo de bits que representa o pacote inteiro (um fluxo de pacote) ou uma única parte em um pacote (um fluxo de parte).

Ao contrário da maioria dos fluxos WebResponse, um fluxo de pacote é buscado usando Stream.Seek. Um fluxo de pacote pode ser usado para criar um objeto de pacote.

Ao operar com o recurso de pacote em um protocolo "http:", PackWebRequest dá suporte ao carregamento progressivo de partes: ou seja, a capacidade de obter recursos de parte em uma ordem arbitrária, sem carregar todos os dados no pacote até os dados da parte.

PackWebRequest fornece apenas recursos para consumo de recursos. Ele não pode ser usado para postar ou enviar dados para um servidor.

Atualmente, PackWebRequest não dá suporte a operações assíncronas (como BeginGetResponse) nem PackWebRequest dá suporte a pacotes aninhados (descritos anteriormente, em "Endereçando partes dentro de um pacote").

O PackageStore

Ao carregar pacotes que têm partes que contêm várias referências a outras partes, o tempo de resposta para solicitações de recursos pode ser aprimorado e o tráfego de rede pode ser reduzido usando o PackageStore. O PackageStore é um dicionário local do aplicativo de referências para abrir pacotes. Cada pacote registrado no PackageStore é identificado por um valor de URI de chave.

O PackageStore permite que PackWebRequest obtenha recursos conforme necessário de um pacote, sem fazer uma solicitação de servidor sempre que outro recurso for necessário desse pacote.

O PackageStore não é alterado automaticamente como resultado de uma chamada para PackWebRequest. Ele deve ser modificado explicitamente. Há dois métodos públicos usados para adicionar ou remover referências para abrir pacotes no PackageStore: Package.AddPackage e Package.RemovePackage.

A política de cache padrão (CacheIfAvailable) definida em PackWebRequest faz com que a classe tente usar o PackageStore para obter o pacote. PackWebRequest pode ser forçado a ignorar o conteúdo do PackageStore ao obter recursos, definindo a política de cache como BypassCache, conforme descrito na próxima seção, "Políticas de Cache".

Ao obter os bits de um pacote ou parte de acordo com a política de cache padrão, PackWebRequest primeiro verifica o PackageStore para ver se há um pacote registrado com uma chave que é igual ao componente de autoridade do URI "pack:". Se o PackageStore não contiver o pacote para a chave, PackWebRequest criará uma WebRequest interna para baixar o recurso usando o componente de autoridade do URI "pack:".

Políticas de cache

As políticas de cache definem as regras usadas para determinar se uma solicitação de recurso pode ser preenchida usando uma cópia armazenada em cache do recurso.

Ao usar PackWebRequest, há dois níveis de política de cache que podem ser definidos explicitamente. Uma política de cache pode ser definida para o PackWebRequest em si, controlando a interação com o PackageStore. Além disso, uma política de cache também pode ser definida para o cache controlado por uma WebRequest interna. A WebRequest interna pode ser acessada por PackWebRequest, usando PackWebRequest.GetInternalRequest().

A política de cache definida no WebRequest interno não terá efeito se PackWebRequest.CachePolicy estiver definido como CacheOnly, fazendo com que o recurso de pacote seja obtido do PackageStore.

PackWebRequest.CachePolicy dá suporte a um subconjunto de políticas, conforme listado abaixo, devido aos recursos específicos do PackageStore.

Tabela 1. Políticas PackWebRequest.CachePolicy

Cachepolicy Descrição
BypassCache Ignorar entradas packageStore com um URI correspondente.
Cacheonly Considere apenas entradas PackageStore (nunca crie uma WebRequest para consultar dados no servidor).
CacheIfAvailable Inspecione o PackageStore e use qualquer pacote lá se um for encontrado; caso contrário, faça uma solicitação de rede para o recurso indicado pelo URI do pacote (o URI interno do URI "pack:"). Esse é o padrão.

Para PackWebRequest, definir todos os outros valores CachePolicy resulta em uma WebException.

Carregamento progressivo

PackWebRequest pode carregar progressivamente uma parte do pacote quando o pacote é acessado pelo protocolo "http:". O carregamento progressivo permite que os aplicativos acessem recursos de parte antes que todo o pacote esteja disponível localmente. O recurso de carregamento progressivo de PackWebRequest é automático: o aplicativo de chamada experimenta o desempenho aprimorado sem intervir.

O carregamento progressivo baseia-se na criação de "solicitações de intervalo de bytes" para recursos, conforme definido no protocolo "http:" 1.1. O formato de arquivo ZIP, usado para armazenar pacotes em forma física, se beneficia desse mecanismo, pois o formato de arquivo ZIP mantém informações importantes em um "diretório central" no final físico do arquivo.

Depois de solicitar um pacote inteiro usando PackWebRequest, o serviço começa a retornar um fluxo no qual um chamador pode procurar. Quando um pacote é aberto no fluxo fornecido pelo PackWebRequest, o chamador pode obter partes mais rapidamente do que ao fazer solicitações diretas usando, por exemplo, o protocolo "http:".

Serviços para avaliar e decompor URIs

Identificando nomes de partes de relação retornados pela classe de pacote

Ao gerenciar uma coleção de partes obtidas usando o método Package.GetParts , as partes de relação podem ser identificadas para que possam ser tratadas separadamente de outras partes. O PackUriHelper.IsRelationshipPartUri é usado para identificar se uma parte é uma parte do relacionamento.

Exemplo: PackUriHelper.IsRelationshipPartUri

//Given the URI for a part

Uri partUri = new Uri("/_rels/sports.rels", UriKind.Relative);

bool isRelationshipPart = PackUriHelper.IsRelationshipPartUri(PartUri);

//The resulting isRelationshipPart value is "TRUE"

Dois outros métodos PackUriHelper estão disponíveis para trabalhar com nomes de partes de relação. PackUriHelper.GetRelationshipPartUri retorna um nome de parte da relação dado um nome de parte de origem. PackUriHelper.GetSourcePartUriFromRelationshipPartUri retorna o nome da parte de origem para um determinado nome de parte da relação.

Comparando URIs para equivalência

Um aplicativo que usa um cache para armazenar partes ao produzir ou consumir um pacote pode precisar executar verificações de nomes de parte equivalentes. O método PackUriHelper.ComparePartUri verifica a equivalência de nomes de parte.

Exemplo: PackUriHelper.ComparePartUri

//Given two part names in the same package
//firstPartName = "/a.xaml"
//secondPartName = "/A.xaml"

//Use PackUriHelper.ComparePartUri to identify if the names 
//are equivalent.

Bool isSamePartName = PackUriHelper.ComparePartUri 
               (firstPartName, secondPartName);

//The resulting isSamePartName value is "TRUE"

Para determinar a equivalência lexical de dois URIs "pack:", use o método PackUriHelper.ComparePackUri .

Exemplo: PackUriHelper.ComparePackUri

//Given two "pack:" URIs
//firstPackUri =
// "PACK://HTTP%3A,,WWW.NEWSDOCS.COM,local,today.container
// /FILES/FIXEDDOC.XAML"
//secondPackUri = 
// "pack://http%3a,,www.newsdocs.com,local,today.container
// /files/fixeddoc.xaml"

//Use PackUriHelper.ComparePackUri to identify if the same resource 
//is targeted.

bool isSameResource = PackUriHelper.ComparePackUri 
            (firstPackUri, secondPackUri);

//The resulting isSameResource value is "TRUE"

Extraindo URIs de componente de um URI "pack:"

Para extrair o URI do pacote de componentes e o URI da parte de um URI "pack:", use os métodos PackUriHelper.GetPackageUri e PackUriHelper.GetPartUri, respectivamente.

Exemplo: PackUriHelper.GetPackageUri

//Given the "pack:" URI for a package

Uri packUri = "pack://http%3a,,www.newsdocs.com,local,today.container
            /files/abc.xaml";

//Use PackUriHelper.GetPackageUri to obtain the URI of the package

Uri packageUri = new PackUriHelper.GetPackageUri(packUri);

//The resulting packageUri value is
//"http://www.newsdocs.com/local/today.container"

Exemplo: Exemplo de GetPartUri

//Given the "pack:" URI for a part

Uri packUri = "pack://http%3a,,www.newsdocs.com,local,today.container
         /files/abc.xaml";

//Use PackUriHelper.GetPartUri to obtain the URI of the part

Uri partUri = new PackUriHelper.GetPartUri(packUri);

//The resulting partUri value is "/files/abc.xaml"

Referências

Open Packaging Conventions

URI (Uniform Resource Identifier): sintaxe genérica

Open XML Paper Specification

IRIs (Identificadores de Recursos Internacionalizados)