Carregar arquivos (C#)

por Scott Mitchell

Baixar PDF

Saiba como permitir que os usuários carreguem arquivos binários (como Word ou documentos PDF) em seu site onde eles podem ser armazenados no sistema de arquivos do servidor ou no banco de dados.

Introdução

Todos os tutoriais que examinamos até agora funcionaram exclusivamente com dados de texto. No entanto, muitos aplicativos têm modelos de dados que capturam dados de texto e binários. Um site de namoro online pode permitir que os usuários carreguem uma imagem para associar ao seu perfil. Um site de recrutamento pode permitir que os usuários carreguem seu currículo como um documento microsoft Word ou PDF.

Trabalhar com dados binários adiciona um novo conjunto de desafios. Devemos decidir como os dados binários são armazenados no aplicativo. A interface usada para inserir novos registros deve ser atualizada para permitir que o usuário carregue um arquivo de seu computador e etapas extras devem ser executadas para exibir ou fornecer um meio para baixar os dados binários associados a um registro. Neste tutorial e nos próximos três, exploraremos como colocar esses desafios em obstáculos. Ao final desses tutoriais, criaremos um aplicativo totalmente funcional que associa uma imagem e um folheto pdf a cada categoria. Neste tutorial específico, examinaremos diferentes técnicas para armazenar dados binários e exploraremos como permitir que os usuários carreguem um arquivo de seu computador e o salvem no sistema de arquivos do servidor Web.

Observação

Dados binários que fazem parte de um modelo de dados do aplicativo às vezes são chamados de BLOB, um acrônimo para Binary Large OBject. Nestes tutoriais, optei por usar os dados binários de terminologia, embora o termo BLOB seja sinônimo.

Etapa 1: Criando as páginas da Web Trabalhando com Dados Binários

Antes de começarmos a explorar os desafios associados à adição de suporte para dados binários, vamos primeiro levar um momento para criar as páginas de ASP.NET em nosso projeto de site que precisaremos para este tutorial e os próximos três. Comece adicionando uma nova pasta chamada BinaryData. Em seguida, adicione as seguintes ASP.NET páginas a essa pasta, certificando-se de associar cada página à Site.master página master:

  • Default.aspx
  • FileUpload.aspx
  • DisplayOrDownloadData.aspx
  • UploadInDetailsView.aspx
  • UpdatingAndDeleting.aspx

Adicionar as páginas de ASP.NET para os tutoriais de Data-Related binários

Figura 1: Adicionar as páginas de ASP.NET para os tutoriais de Data-Related binários

Assim como nas outras pastas, Default.aspx na BinaryData pasta listará os tutoriais em sua seção. Lembre-se de que o SectionLevelTutorialListing.ascx Controle de Usuário fornece essa funcionalidade. Portanto, adicione esse Controle de Usuário ao Default.aspx arrastando-o do Gerenciador de Soluções para o modo design da página.

Adicione o controle de usuário SectionLevelTutorialListing.ascx ao Default.aspx

Figura 2: Adicionar o controle de SectionLevelTutorialListing.ascx usuário a Default.aspx (clique para exibir a imagem em tamanho real)

Por fim, adicione essas páginas como entradas ao Web.sitemap arquivo. Especificamente, adicione a seguinte marcação após o Enhancing the GridView <siteMapNode>:

<siteMapNode 
    title="Working with Binary Data" 
    url="~/BinaryData/Default.aspx" 
    description="Extend the data model to include collecting binary data.">
    
    <siteMapNode 
        title="Uploading Files" 
        url="~/BinaryData/FileUpload.aspx" 
        description="Examine the different ways to store binary data on the 
                     web server and see how to accept uploaded files from users 
                     with the FileUpload control." />
    <siteMapNode 
        title="Display or Download Binary Data" 
        url="~/BinaryData/DisplayOrDownloadData.aspx" 
        description="Let users view or download the captured binary data." />
    <siteMapNode 
        title="Adding New Binary Data" 
        url="~/BinaryData/UploadInDetailsView.aspx" 
        description="Learn how to augment the inserting interface to 
                     include a FileUpload control." />
    <siteMapNode 
        title="Updating and Deleting Existing Binary Data" 
        url="~/BinaryData/UpdatingAndDeleting.aspx" 
        description="Learn how to update and delete existing binary data." />
</siteMapNode>

Depois de atualizar Web.sitemap, reserve um momento para exibir o site de tutoriais por meio de um navegador. O menu à esquerda agora inclui itens para os tutoriais Trabalhando com Dados Binários.

O mapa do site agora inclui entradas para os tutoriais trabalhando com dados binários

Figura 3: O mapa do site agora inclui entradas para os tutoriais trabalhando com dados binários

Etapa 2: Decidir onde armazenar os dados binários

Os dados binários associados ao modelo de dados do aplicativo podem ser armazenados em um dos dois locais: no sistema de arquivos do servidor Web com uma referência ao arquivo armazenado no banco de dados; ou diretamente no próprio banco de dados (consulte a Figura 4). Cada abordagem tem seu próprio conjunto de prós e contras e merece uma discussão mais detalhada.

Os dados binários podem ser armazenados no sistema de arquivos ou diretamente no banco de dados

Figura 4: Os dados binários podem ser armazenados no sistema de arquivos ou diretamente no banco de dados (clique para exibir a imagem em tamanho real)

Imagine que queríamos estender o banco de dados Northwind para associar uma imagem a cada produto. Uma opção seria armazenar esses arquivos de imagem no sistema de arquivos do servidor Web e registrar o caminho na Products tabela. Com essa abordagem, adicionaríamos uma ImagePath coluna à Products tabela do tipo varchar(200), talvez. Quando um usuário carregou uma imagem para Chai, essa imagem pode ser armazenada no sistema de arquivos do servidor Web em , em ~/Images/Tea.jpgque ~ representa o caminho físico do aplicativo. Ou seja, se o site tiver raiz no caminho C:\Websites\Northwind\físico , ~/Images/Tea.jpg será equivalente a C:\Websites\Northwind\Images\Tea.jpg. Depois de carregar o arquivo de imagem, atualizaríamos o registro Chai na Products tabela para que sua ImagePath coluna referenciasse o caminho da nova imagem. Poderíamos usar ~/Images/Tea.jpg ou apenas Tea.jpg se decidirmos que todas as imagens do produto seriam colocadas na pasta do Images aplicativo.

As vantagens main de armazenar os dados binários no sistema de arquivos são:

  • Facilidade de implementação , como veremos em breve, armazenar e recuperar dados binários armazenados diretamente no banco de dados envolve um pouco mais de código do que ao trabalhar com dados por meio do sistema de arquivos. Além disso, para que um usuário exiba ou baixe dados binários, ele deve receber uma URL para esses dados. Se os dados residirem no sistema de arquivos do servidor Web, a URL será simples. No entanto, se os dados forem armazenados no banco de dados, será necessário criar uma página da Web que recupere e retorne os dados do banco de dados.
  • Acesso mais amplo aos dados binários , os dados binários podem precisar estar acessíveis a outros serviços ou aplicativos, que não podem extrair os dados do banco de dados. Por exemplo, as imagens associadas a cada produto também podem precisar estar disponíveis para os usuários por meio do FTP. Nesse caso, gostaríamos de armazenar os dados binários no sistema de arquivos.
  • Desempenho se os dados binários forem armazenados no sistema de arquivos, a demanda e o congestionamento de rede entre o servidor de banco de dados e o servidor Web serão menores do que se os dados binários forem armazenados diretamente no banco de dados.

A desvantagem main de armazenar dados binários no sistema de arquivos é que ele separa os dados do banco de dados. Se um registro for excluído da Products tabela, o arquivo associado no sistema de arquivos do servidor Web não será excluído automaticamente. Devemos escrever código extra para excluir o arquivo ou o sistema de arquivos ficará cheio de arquivos órfãos não utilizados. Além disso, ao fazer backup do banco de dados, também devemos fazer backups dos dados binários associados no sistema de arquivos. Mover o banco de dados para outro site ou servidor apresenta desafios semelhantes.

Como alternativa, os dados binários podem ser armazenados diretamente em um banco de dados do Microsoft SQL Server 2005 criando uma coluna do tipo varbinary. Assim como acontece com outros tipos de dados de comprimento variável, você pode especificar um comprimento máximo dos dados binários que podem ser mantidos nesta coluna. Por exemplo, para reservar no máximo 5.000 bytes, use varbinary(5000); varbinary(MAX) permite o tamanho máximo de armazenamento, cerca de 2 GB.

A vantagem main de armazenar dados binários diretamente no banco de dados é o acoplamento rígido entre os dados binários e o registro do banco de dados. Isso simplifica muito as tarefas de administração de banco de dados, como backups ou mover o banco de dados para um site ou servidor diferente. Além disso, excluir um registro exclui automaticamente os dados binários correspondentes. Também há benefícios mais sutis de armazenar os dados binários no banco de dados. Consulte Armazenando arquivos binários diretamente no banco de dados usando ASP.NET 2.0 para obter uma discussão mais detalhada.

Observação

No Microsoft SQL Server 2000 e versões anteriores, o varbinary tipo de dados tinha um limite máximo de 8.000 bytes. Para armazenar até 2 GB de dados binários, o image tipo de dados precisa ser usado. Com a adição de MAX em SQL Server 2005, no entanto, o image tipo de dados foi preterido. Ele ainda tem suporte para compatibilidade com versões anteriores, mas a Microsoft anunciou que o image tipo de dados será removido em uma versão futura do SQL Server.

Se você estiver trabalhando com um modelo de dados mais antigo, poderá ver o image tipo de dados. A tabela do banco de Categories dados Northwind tem uma Picture coluna que pode ser usada para armazenar os dados binários de um arquivo de imagem para a categoria. Como o banco de dados Northwind tem suas raízes no Microsoft Access e versões anteriores do SQL Server, essa coluna é do tipo image.

Para este tutorial e os próximos três, usaremos as duas abordagens. A Categories tabela já tem uma Picture coluna para armazenar o conteúdo binário de uma imagem para a categoria. Adicionaremos uma coluna adicional, BrochurePath, para armazenar um caminho para um PDF no sistema de arquivos do servidor Web que pode ser usado para fornecer uma visão geral polida e de qualidade de impressão da categoria.

Etapa 3: Adicionar aBrochurePathcoluna àCategoriestabela

Atualmente, a tabela Categorias tem apenas quatro colunas: CategoryID, CategoryName, Descriptione Picture. Além desses campos, precisamos adicionar um novo que aponte para o folheto da categoria (se houver). Para adicionar essa coluna, vá para a Explorer servidor, faça uma busca detalhada nas Tabelas, clique com o botão direito do Categories mouse na tabela e escolha Abrir Definição de Tabela (consulte a Figura 5). Se você não vir o servidor Explorer, abra-o selecionando a opção Servidor Explorer no menu Exibir ou pressione Ctrl+Alt+S.

Adicione uma nova varchar(200) coluna à Categories tabela que é nomeada BrochurePath e permite NULL s e clique no ícone Salvar (ou pressione Ctrl+S).

Adicionar uma coluna BrochurePath à tabela Categories

Figura 5: Adicionar uma BrochurePath coluna à Categories tabela (clique para exibir a imagem em tamanho real)

Etapa 4: Atualizando a arquitetura para usar asPicturecolunas eBrochurePath

O CategoriesDataTable na DAL (Camada de Acesso a Dados) atualmente tem quatro DataColumn s definidos: CategoryID, CategoryName, Descriptione NumberOfProducts. Quando projetamos originalmente essa DataTable no tutorial Criando uma camada de acesso a dados , a CategoriesDataTable única tinha as três primeiras colunas; a NumberOfProducts coluna foi adicionada no tutorial Mestre/Detalhe usando uma lista com marcadores de registros mestres com um tutorial datalist de detalhes .

Conforme discutido em Criando uma camada de acesso a dados, as DataTables no Conjunto de Dados Tipados compõem os objetos de negócios. Os TableAdapters são responsáveis por se comunicar com o banco de dados e preencher os objetos de negócios com os resultados da consulta. O CategoriesDataTable é preenchido pelo CategoriesTableAdapter, que tem três métodos de recuperação de dados:

  • GetCategories()executa a consulta main tableAdapter e retorna os CategoryIDcampos , CategoryNamee Description de todos os registros na Categories tabela. A consulta main é usada pelos métodos e Update gerados automaticamenteInsert.
  • GetCategoryByCategoryID(categoryID) retorna os CategoryIDcampos , CategoryNamee Description da categoria cuja CategoryIDcategoryID é igual a.
  • GetCategoriesAndNumberOfProducts() – retorna os CategoryIDcampos , CategoryNamee Description para todos os registros na Categories tabela. Também usa uma subconsulta para retornar o número de produtos associados a cada categoria.

Observe que nenhuma dessas consultas retorna as Categories tabelas ou BrochurePathPicture colunas; nem o CategoriesDataTable fornece DataColumn para esses campos. Para trabalhar com a Imagem e BrochurePath as propriedades, precisamos primeiro adicioná-las ao CategoriesDataTable e, em seguida, atualizar a CategoriesTableAdapter classe para retornar essas colunas.

Adicionando osPictureeBrochurePath``DataColumn s

Comece adicionando essas duas colunas ao CategoriesDataTable. Clique com o botão direito do CategoriesDataTable mouse no cabeçalho s, selecione Adicionar no menu de contexto e escolha a opção Coluna. Isso criará um novo DataColumn na DataTable chamado Column1. Renomeie esta coluna como Picture. No janela Propriedades, defina a DataColumn propriedade s DataType como System.Byte[] (essa não é uma opção na lista suspensa; você precisa digitá-la).

Criar uma imagem nomeada datacolumn cujo DataType é System.Byte[]

Figura 6: Criar um DataColumn Nomeado Picture cujo DataType é System.Byte[] (Clique para exibir a imagem em tamanho real)

Adicione outro DataColumn ao DataTable, nomeando-o BrochurePath usando o valor padrão DataType (System.String).

Retornando osPicturevalores eBrochurePathdo TableAdapter

Com esses dois DataColumn s adicionados ao CategoriesDataTable, estamos prontos para atualizar o CategoriesTableAdapter. Poderíamos ter esses dois valores de coluna retornados na consulta main TableAdapter, mas isso traria de volta os dados binários sempre que o GetCategories() método fosse invocado. Em vez disso, vamos atualizar a consulta main TableAdapter para trazer de volta BrochurePath e criar um método de recuperação de dados adicional que retorna uma coluna de categoria específicaPicture.

Para atualizar a consulta main TableAdapter, clique com o botão direito do CategoriesTableAdapter mouse no cabeçalho s e escolha a opção Configurar no menu de contexto. Isso apresenta o Assistente de Configuração do Adaptador de Tabela, que vimos em vários tutoriais anteriores. Atualize a consulta para trazer de volta o BrochurePath e clique em Concluir.

Atualizar a lista de colunas na instrução SELECT para também retornar BrochurePath

Figura 7: Atualizar a Lista de Colunas na SELECT Instrução para Também Retornar BrochurePath (Clique para exibir a imagem em tamanho real)

Ao usar instruções SQL ad hoc para o TableAdapter, atualizar a lista de colunas na consulta main atualiza a lista de colunas para todos os métodos de SELECT consulta no TableAdapter. Isso significa que o GetCategoryByCategoryID(categoryID) método foi atualizado para retornar a BrochurePath coluna, que pode ser o que queríamos. No entanto, ele também atualizou a lista de colunas no GetCategoriesAndNumberOfProducts() método , removendo a subconsulta que retorna o número de produtos para cada categoria! Portanto, precisamos atualizar a consulta desse SELECT método. Clique com o botão direito do GetCategoriesAndNumberOfProducts() mouse no método, escolha Configurar e reverter a SELECT consulta de volta ao valor original:

SELECT CategoryID, CategoryName, Description, 
       (SELECT COUNT(*) 
            FROM Products p 
            WHERE p.CategoryID = c.CategoryID) 
       as NumberOfProducts
FROM Categories c

Em seguida, crie um novo método TableAdapter que retorna um valor de coluna de Picture categoria específico. Clique com o botão direito do CategoriesTableAdapter mouse no cabeçalho s e escolha a opção Adicionar Consulta para iniciar o Assistente de Configuração de Consulta tableAdapter. A primeira etapa deste assistente nos pergunta se queremos consultar dados usando uma instrução SQL ad hoc, um novo procedimento armazenado ou um existente. Selecione Usar instruções SQL e clique em Avançar. Como retornaremos uma linha, escolha a opção SELECT que retorna linhas na segunda etapa.

Selecione a opção Usar instruções SQL

Figura 8: selecione a opção Usar instruções SQL (Clique para exibir a imagem em tamanho real)

Como a consulta retornará um registro da tabela Categorias, escolha SELECT, que retorna linhas

Figura 9: como a consulta retornará um registro da tabela Categorias, escolha SELECT que retorna linhas (Clique para exibir a imagem em tamanho real)

Na terceira etapa, insira a seguinte consulta SQL e clique em Avançar:

SELECT     CategoryID, CategoryName, Description, BrochurePath, Picture
FROM       Categories
WHERE      CategoryID = @CategoryID

A última etapa é escolher o nome do novo método. Use FillCategoryWithBinaryDataByCategoryID e GetCategoryWithBinaryDataByCategoryID para os padrões Preencher uma DataTable e Retornar um DataTable, respectivamente. Clique em Concluir para concluir o assistente.

Escolher os nomes para os métodos TableAdapter s

Figura 10: escolha os nomes para os métodos tableAdapter (clique para exibir a imagem em tamanho real)

Observação

Depois de concluir o Assistente de Configuração de Consulta do Adaptador de Tabela, você poderá ver uma caixa de diálogo informando que o novo texto de comando retorna dados com esquema diferente do esquema da consulta main. Em suma, o assistente observa que a consulta GetCategories() main do TableAdapter retorna um esquema diferente daquele que acabamos de criar. Mas isso é o que queremos, para que você possa ignorar essa mensagem.

Além disso, tenha em mente que, se você estiver usando instruções SQL ad hoc e usar o assistente para alterar a consulta main do TableAdapter em algum momento posterior, ela modificará a GetCategoryWithBinaryDataByCategoryID lista de colunas da instrução do SELECT método para incluir apenas essas colunas da consulta main (ou seja, ela removerá a Picture coluna da consulta). Você precisará atualizar manualmente a lista de colunas para retornar a Picture coluna, semelhante ao que fizemos com o GetCategoriesAndNumberOfProducts() método anteriormente nesta etapa.

Depois de adicionar os dois DataColumn s ao método e GetCategoryWithBinaryDataByCategoryID ao CategoriesTableAdapter, essas classes no Designer Typed DataSet devem ser semelhantes à CategoriesDataTable captura de tela na Figura 11.

A Designer dataset inclui as novas colunas e o método

Figura 11: o Designer dataset inclui as novas colunas e o método

Atualizando a BLL (Camada lógica de negócios)

Com o DAL atualizado, tudo o que resta é aumentar a BLL (Camada lógica de negócios) para incluir um método para o novo CategoriesTableAdapter método. Adicione o seguinte método à classe CategoriesBLL:

[System.ComponentModel.DataObjectMethodAttribute
    (System.ComponentModel.DataObjectMethodType.Select, false)] 
public Northwind.CategoriesDataTable 
    GetCategoryWithBinaryDataByCategoryID(int categoryID)
{
    return Adapter.GetCategoryWithBinaryDataByCategoryID(categoryID);
}

Etapa 5: Carregar um arquivo do cliente para o servidor Web

Ao coletar dados binários, geralmente esses dados são fornecidos por um usuário final. Para capturar essas informações, o usuário precisa ser capaz de carregar um arquivo do computador para o servidor Web. Em seguida, os dados carregados precisam ser integrados ao modelo de dados, o que pode significar salvar o arquivo no sistema de arquivos do servidor Web e adicionar um caminho ao arquivo no banco de dados ou gravar o conteúdo binário diretamente no banco de dados. Nesta etapa, veremos como permitir que um usuário carregue arquivos do computador para o servidor. No próximo tutorial, voltaremos nossa atenção para a integração do arquivo carregado com o modelo de dados.

ASP.NET novo controle Web FileUpload do ASP.NET 2.0 fornece um mecanismo para que os usuários enviem um arquivo do computador para o servidor Web. O controle FileUpload é renderizado como um <input> elemento cujo type atributo está definido como arquivo, que os navegadores exibem como uma caixa de texto com um botão Procurar. Clicar no botão Procurar abre uma caixa de diálogo da qual o usuário pode selecionar um arquivo. Quando o formulário é postado novamente, o conteúdo do arquivo selecionado é enviado junto com o postback. No lado do servidor, as informações sobre o arquivo carregado podem ser acessadas por meio das propriedades do controle FileUpload.

Para demonstrar o carregamento de arquivos, abra a FileUpload.aspx página na BinaryData pasta, arraste um controle FileUpload da Caixa de Ferramentas para o Designer e defina a propriedade do ID controle como UploadTest. Em seguida, adicione um controle Web Button definindo suas ID propriedades e Text como UploadButton e Carregar Arquivo Selecionado, respectivamente. Por fim, coloque um controle Web rótulo abaixo do Botão, desmarque sua Text propriedade e defina sua ID propriedade como UploadDetails.

Adicionar um controle FileUpload à página ASP.NET

Figura 12: Adicionar um controle FileUpload à página ASP.NET (Clique para exibir a imagem em tamanho real)

A Figura 13 mostra esta página quando exibida por meio de um navegador. Observe que clicar no botão Procurar abre uma caixa de diálogo de seleção de arquivo, permitindo que o usuário escolha um arquivo no computador. Depois que um arquivo é selecionado, clicar no botão Carregar Arquivo Selecionado causa um postback que envia o conteúdo binário do arquivo selecionado para o servidor Web.

O usuário pode selecionar um arquivo para carregar de seu computador para o servidor

Figura 13: o usuário pode selecionar um arquivo para carregar do computador para o servidor (clique para exibir a imagem em tamanho real)

No postback, o arquivo carregado pode ser salvo no sistema de arquivos ou seus dados binários podem ser trabalhados diretamente por meio de um Stream. Para este exemplo, vamos criar uma ~/Brochures pasta e salvar o arquivo carregado lá. Comece adicionando a Brochures pasta ao site como uma subpasta do diretório raiz. Em seguida, crie um manipulador de eventos para o UploadButton evento s Click e adicione o seguinte código:

protected void UploadButton_Click(object sender, EventArgs e)
{
    if (UploadTest.HasFile == false)
    {
        // No file uploaded!
        UploadDetails.Text = "Please first select a file to upload...";            
    }
    else
    {
        // Display the uploaded file's details
        UploadDetails.Text = string.Format(
                @"Uploaded file: {0}<br />
                  File size (in bytes): {1:N0}<br />
                  Content-type: {2}", 
                  UploadTest.FileName, 
                  UploadTest.FileBytes.Length,
                  UploadTest.PostedFile.ContentType);
        // Save the file
        string filePath = 
            Server.MapPath("~/Brochures/" + UploadTest.FileName);
        UploadTest.SaveAs(filePath);
    }
}

O controle FileUpload fornece uma variedade de propriedades para trabalhar com os dados carregados. Por exemplo, a HasFile propriedade indica se um arquivo foi carregado pelo usuário, enquanto a FileBytes propriedade fornece acesso aos dados binários carregados como uma matriz de bytes. O Click manipulador de eventos começa garantindo que um arquivo tenha sido carregado. Se um arquivo tiver sido carregado, o Rótulo mostrará o nome do arquivo carregado, seu tamanho em bytes e seu tipo de conteúdo.

Observação

Para garantir que o usuário carregue um arquivo, você pode marcar a HasFile propriedade e exibir um aviso se ele for falseou você poderá usar o controle RequiredFieldValidator.

O FileUpload SaveAs(filePath) salva o arquivo carregado no filePath especificado. filePath deve ser um caminho físico (C:\Websites\Brochures\SomeFile.pdf) em vez de um caminhovirtual (/Brochures/SomeFile.pdf). O Server.MapPath(virtPath) método usa um caminho virtual e retorna seu caminho físico correspondente. Aqui, o caminho virtual é ~/Brochures/fileName, em que fileName é o nome do arquivo carregado. Consulte Método Server.MapPath para obter mais informações sobre caminhos virtuais e físicos e usando Server.MapPath.

Depois de concluir o Click manipulador de eventos, tire um momento para testar a página em um navegador. Clique no botão Procurar e selecione um arquivo no disco rígido e clique no botão Carregar Arquivo Selecionado. O postback enviará o conteúdo do arquivo selecionado para o servidor Web, que exibirá informações sobre o arquivo antes de salvá-lo na ~/Brochures pasta. Depois de carregar o arquivo, retorne ao Visual Studio e clique no botão Atualizar no Gerenciador de Soluções. Você deve ver o arquivo que acabou de carregar na pasta ~/Brochures!

O EvolutionValley.jpg de arquivo foi carregado no servidor Web

Figura 14: o arquivo EvolutionValley.jpg foi carregado no servidor Web (clique para exibir a imagem em tamanho real)

EvolutionValley.jpg foi salvo na pasta ~/Brochures

Figura 15: EvolutionValley.jpg foi salva na ~/Brochures pasta

Sutilezas com o salvamento de arquivos carregados no sistema de arquivos

Há várias sutilezas que devem ser abordadas ao salvar o carregamento de arquivos no sistema de arquivos do servidor Web. Primeiro, há o problema de segurança. Para salvar um arquivo no sistema de arquivos, o contexto de segurança no qual a página ASP.NET está sendo executada deve ter permissões de Gravação. O ASP.NET Development Web Server é executado no contexto da sua conta de usuário atual. Se você estiver usando o IIS (Serviços de Informações da Internet) da Microsoft como servidor Web, o contexto de segurança dependerá da versão do IIS e de sua configuração.

Outro desafio de salvar arquivos no sistema de arquivos gira em torno da nomenclatura dos arquivos. Atualmente, nossa página salva todos os arquivos carregados no ~/Brochures diretório usando o mesmo nome que o arquivo no computador do cliente. Se o Usuário A carregar um folheto com o nome Brochure.pdf, o arquivo será salvo como ~/Brochure/Brochure.pdf. Mas e se algum tempo depois o Usuário B carregar um arquivo de folheto diferente que tenha o mesmo nome de arquivo (Brochure.pdf)? Com o código que temos agora, o arquivo S do Usuário A será substituído pelo upload do Usuário B.

Há várias técnicas para resolver conflitos de nome de arquivo. Uma opção é proibir o carregamento de um arquivo se já existir um com o mesmo nome. Com essa abordagem, quando o Usuário B tenta carregar um arquivo chamado Brochure.pdf, o sistema não salva o arquivo e exibe uma mensagem informando ao Usuário B para renomear o arquivo e tentar novamente. Outra abordagem é salvar o arquivo usando um nome de arquivo exclusivo, que pode ser um GUID (identificador global exclusivo) ou o valor das colunas de chave primária do registro de banco de dados correspondente (supondo que o upload esteja associado a uma linha específica no modelo de dados). No próximo tutorial, exploraremos essas opções mais detalhadamente.

Desafios envolvidos com grandes quantidades de dados binários

Esses tutoriais pressupõem que os dados binários capturados são modestos em tamanho. Trabalhar com grandes quantidades de arquivos de dados binários que são vários megabytes ou maiores apresenta novos desafios que estão além do escopo desses tutoriais. Por exemplo, por padrão, ASP.NET rejeitará uploads de mais de 4 MB, embora isso possa ser configurado por meio do <httpRuntime> elemento em Web.config. O IIS também impõe suas próprias limitações de tamanho de upload de arquivo. Além disso, o tempo necessário para carregar arquivos grandes pode exceder os 110 segundos padrão ASP.NET aguardará uma solicitação. Também há problemas de memória e desempenho que surgem ao trabalhar com arquivos grandes.

O controle FileUpload é impraticável para uploads de arquivos grandes. Como o conteúdo do arquivo está sendo postado no servidor, o usuário final deve aguardar pacientemente sem qualquer confirmação de que o upload está progredindo. Isso não é tanto um problema ao lidar com arquivos menores que podem ser carregados em alguns segundos, mas pode ser um problema ao lidar com arquivos maiores que podem levar minutos para serem carregados. Há uma variedade de controles de upload de arquivos de terceiros que são mais adequados para lidar com uploads grandes e muitos desses fornecedores fornecem indicadores de progresso e gerenciadores de upload do ActiveX que apresentam uma experiência de usuário muito mais elegante.

Se o aplicativo precisar lidar com arquivos grandes, você precisará investigar cuidadosamente os desafios e encontrar soluções adequadas para suas necessidades específicas.

Resumo

A criação de um aplicativo que precisa capturar dados binários apresenta uma série de desafios. Neste tutorial, exploramos os dois primeiros: decidir onde armazenar os dados binários e permitir que um usuário carregue conteúdo binário por meio de uma página da Web. Nos próximos três tutoriais, veremos como associar os dados carregados a um registro no banco de dados, bem como exibir os dados binários junto com seus campos de dados de texto.

Programação feliz!

Leitura Adicional

Para obter mais informações sobre os tópicos discutidos neste tutorial, consulte os seguintes recursos:

Sobre o autor

Scott Mitchell, autor de sete livros do ASP/ASP.NET e fundador da 4GuysFromRolla.com, trabalha com tecnologias da Microsoft Web desde 1998. Scott trabalha como consultor independente, treinador e escritor. Seu último livro é Sams Teach Yourself ASP.NET 2.0 em 24 Horas. Ele pode ser contatado em mitchell@4GuysFromRolla.com. ou através de seu blog, que pode ser encontrado em http://ScottOnWriting.NET.

Agradecimentos Especiais

Esta série de tutoriais foi revisada por muitos revisores úteis. Os principais revisores deste tutorial foram Teresa Murphy e Berne Leigh. Interessado em revisar meus próximos artigos do MSDN? Nesse caso, deixe-me uma linha em mitchell@4GuysFromRolla.com.