posts - 112, comments - 174, trackbacks - 1

sabato 29 novembre 2008

Umbraco, importazione di file in Media

Con questo post inauguro (si fa per dire) una nuova sezione dedicata al CMS Open Source (scritto in C#) Umbraco. Durante questa settimana, abbiamo avuto la necessità di migrare un vecchio sito verso questa piattaforma, il problema principale è stato l'importazione di documenti PDF all'interno della sezione Media di Umbraco, e agganciare l'ID del nodo media  di ogni file, al rispettivo controllo MediaPicker per i rispettivi documenti nella sezione Content.  I  PDF erano situati in una struttura di directory e sottodirectory con un particolare significato. Volevo condividere un piccolo esempio d'importazione per due motivi: per ricordarmelo ;-) e perchè magari qualcuno potrebbe capitare nella mia stessa situazione, in fondo il CMS è open source, quindi mi sembra il minimo...

Supponiamo di avere in Media un Folder denominato Documentazione, il cui nodo ha ID 8734

image

Supponiamo di avere tra i Documet Types, un NodeType denominato PaginaMediaPicker, contenente un Tab denominato content con due proprietà: title (Textstring) e attach (MediaPicker):

image

Inoltre nella sezione Content, supponiamo di avere una nodo denominato Importazione con ID=8806. A questo punto non ci resta che eseguire l'importazione dei dati, per aggiungendo così i documenti PDF nella cartella Documenti PDF della sezione Media, sotto il nodo Documentazione, e i rispettivi documenti di Content (istanze di PaginaMediaPicker) sotto il nodo Importazione. Possiamo creare una classe per l'importazione dei dati, come ad esempio:

1 public class ImportMedia 2 { 3 private umbraco.BusinessLogic.User _user = null; 4 5 public ImportMedia(umbraco.BusinessLogic.User user) 6 { 7 _user = user; 8 } 9 10 /// <summary> 11 /// Crea un nuovo Folder in Media. Se la funzione ha successo, ritorna 12 /// l'id del nodo creato 13 /// </summary> 14 /// <param name="parentId">ID del Parent sotto il quale creare il folder</param> 15 /// <param name="nome">Nome del folder da creare</param> 16 /// <returns></returns> 17 public int MakeFolderMedia(int parentId, string folderName) 18 { 19 try 20 { 21 MediaType folderType = MediaType.GetByAlias("Folder"); 22 Media folder = Media.MakeNew(folderName, folderType, _user, parentId); 23 24 return folder.Id; 25 } 26 catch 27 { 28 return -1; 29 } 30 } 31 32 /// <summary> 33 /// Esegue la scansione ricorsiva della directory 34 /// </summary> 35 /// <param name="fullDirectoryPath">Percorso completo della directory contenente i documenti</param> 36 /// <param name="searchPattern">Pattern di ricerca dei file</param> 37 /// <param name="documentTypeName">Nome del tipo di documento (Document Type) da creare</param> 38 /// <param name="parentContentId">ID del nodo Content a cui aggiungere i nodi di tipo Content</param> 39 /// <param name="parentMediaId">ID del nodo Media a cui aggiungere i nodi documenti caricati</param> 40 public void ScanDirectory(string fullDirectoryPath, string searchPattern, 41 string documentTypeName, int parentContentId, int parentMediaId) 42 { 43 DirectoryInfo dInfo = new DirectoryInfo(fullDirectoryPath); 44 foreach (DirectoryInfo dir in dInfo.GetDirectories()) 45 { 46 ScanDirectory(dir.FullName, searchPattern, documentTypeName, parentContentId, parentMediaId); 47 } 48 49 foreach (FileInfo file in dInfo.GetFiles(searchPattern)) 50 { 51 MediaType fileType = MediaType.GetByAlias("File"); 52 //Crea un oggetto Media, lo inserisce nell'albero sotto il nodo con ID uguale a parentMediaId 53 Media m = Media.MakeNew(file.Name, fileType, _user, parentMediaId); 54 m.getProperty("umbracoFile").Value = UploadFile(file.FullName, 55 m.getProperty("umbracoFile").Id, 56 m.getProperty("umbracoFile").VersionId); 57 58 if (m.Id > 0) 59 MakeDocument(documentTypeName, file.Name, parentContentId, 60 new string[] { "title", "attach" }, 61 new string[] { file.Name, m.Id.ToString() } 62 ); 63 } 64 } 65 66 /// <summary> 67 /// Crea un nuovo documento 68 /// </summary> 69 /// <param name="documentTypeName">Nome del Document Type da creare</param> 70 /// <param name="documentName">Nome del documento</param> 71 /// <param name="parentContentId">ID del nodo Content a cui aggiungere i nodi di tipo Content</param> 72 /// <param name="properties">Nomi delle proprietà del Document Type che devono essere valorizzate</param> 73 /// <param name="values">Valori delle proprietà del Document Type </param> 74 /// <returns></returns> 75 private int MakeDocument(string documentTypeName, string documentName, int parentContentId, 76 string[] properties, string[] values) 77 { 78 79 DocumentType dt = DocumentType.GetByAlias(documentTypeName); 80 81 if (properties.Length == values.Length) 82 { 83 Document d = Document.MakeNew(documentName, dt, _user, parentContentId); 84 85 for (int index = 0; index < properties.Length; index++) 86 d.getProperty(properties[index]).Value = values[index]; 87 88 d.Publish(_user); 89 90 return d.Id; 91 } 92 else 93 { 94 throw new System.Exception("Wrong Data"); 95 } 96 } 97 98 99 private string UploadFile(string fullFilePath, int propertyID, System.Guid versionID) 100 { 101 //Code... 102 } 103 }

Il sorgente completo della classe ImportMedia è in allegato al post. Il codice sopra, può essere utilizzato, ad esempio in una Web Form, nel seguente modo:

1 User user = new User(0); 2 ImportMedia import = new ImportMedia(user); 3 4 //8734, ID del Parent nella sezione Media 5 int mediaParentId = import.MakeFolderMedia(8734, "Documenti PDF"); 6 if (mediaParentId > 0) 7 { 8 //8806, ID del Parent nella sezione Content 9 import.ScanDirectory(@"C:\Percorso_Cartella\PDFs", 10 "*.pdf", "PaginaMediaPicker", 8806, mediaParentId); 11 } 12 else 13 Response.Write("Errore nella creazione del folder in Media");

Una volta eseguito il codice, nella sezione Media, otterremo:

image

Mentre nel Content avremo:

image

Per la corretta esecuzione del codice, in un'applicazione web differente da quella di Umbraco, è necessario impostare correttamente il web.config.

La versione di Umbraco utilizzata è la 3.0.6.

Codice Completo della classe ImportMedia

 

Technorati Tag: ,

posted @ sabato 29 novembre 2008 20.17 | Feedback (0) | Filed Under [ CMS, Umbraco ]

Backup/Restore SMS

Avendo acquistato un nuovo Palmare, è sorto il problema di dover trasferire i dati dal vecchio al nuovo dispositivo, tra i quali i messaggi SMS. Ho trovato questa utility, SmsImport veramente interessante. Oltre ad effettuare il backup ed il riprisinto degli SMS, esporta i dati in un file XML (e questo mi suggerisce la possibilità di creare un'applicazione personalizzata che legge da XML ed importa su un databse SQL Server Mobile) ed in più, seguendo il link indicato è possibile scaricare anche i sorgenti (in VC++). La versione è stata aggiornata dallo sviluppatore che ha progettato il tool, al 9 giugno 2008. L'installazione è veramente molto semplice: è sufficiente copiare il file nel dispositivo ed eseguirlo.

Technorati Tag: ,,,

posted @ sabato 29 novembre 2008 13.28 | Feedback (4) | Filed Under [ Tools ]

venerdì 28 novembre 2008

[OT] Nuovo acquisto...

Dopo il cedimento strutturale :-) del mio HP HW6915 ho dovuto affrontare l'acquisto di un nuovo Palmare, la scelta è ricaduta (complice anche una buona offerta) su un LG KS20

 

 image image

Dopo  più di una settimana che l'utilizzo, sono abbastanza soddisfatto dell'acquisto, unico neo: GPS non integrato, ma dato che in due anni di onorato servizio, ho usato il GPS del mio HP solo tre volte, non è un grande problema. Speriamo duri quanto il suo predecessore ;-)

posted @ venerdì 28 novembre 2008 16.03 | Feedback (2) | Filed Under [ OT ]

martedì 25 novembre 2008

La crisi colpisce anche Google...

Come descritto da questo articolo, neanche il gigante Google è stato risparmiato dall'ondata di crisi internazionale...come andiamo male...

posted @ martedì 25 novembre 2008 17.52 | Feedback (2) | Filed Under [ Varie ed eventuali ]

Image, MemoryStream e file .rdlc

Supponiamo di avere un file di Report in formato .rdlc, e di voler stampare una lista di prodotti visualizzando un'immagine prodotta a run-time e memorizzata in un MemoryStream, piuttosto che utilizzare file d'immagine. Ad esempio, supponiamo di avere nel nostro Database, una tabella denominata Prodotti, contenente 4 colonne:

image

Aggiungiamo al nostro progetto (ad esempio di tipo Web Application) un DataSet tipizzato (dsProdotti)  contenente un DataTable Prodotti, a cui andiamo ad aggiungere una colonna denominata  Immagine, con proprietà DataType impostata su System.Byte[]:

image

Aggiungiamo un nuovo file di Report (Report1.rdlc), nel designer del report, dalla toolbox degli strumenti, trasciniamo nella sezione Body, un item Table che configuriamo  opportunamente:

image

Come si evince dalla figura, nell'ultima colonna della Table, è stato aggiunto un controllo Image. Affinchè il tutto funzioni correttamente, è necessario impostare correttamente le proprietà di questo controllo, ovvero:

  1. La proprietà Source deve essere impostata su Database
  2. La proprietà MIMEType deve essere impostata sul tipo di immagine che si vuole visualizzare (images/gif, image/jpeg etc...)
  3. La proprietà Value deve essere impostata sul valore campo contenente lo Stream di byte, nello specifico: =Fields!Immagine.Value

Agganciato il report ad un opportuno controllo ReportViewer  non resta che scrivere il codice per recuperare i dati dal Database e popolare un opportuno DataTable, da utilizzare come sorgente dati per il Report:

1 DsProdotti dsProdotti = new DsProdotti(); 2 3 dsProdotti.Prodotti.RowChanged += new DataRowChangeEventHandler(Prodotti_RowChanged); 4 5 using (DsProdottiTableAdapters.ProdottiTableAdapter prodottiAdapter = new ReportConImmaginiStream.DsProdottiTableAdapters.ProdottiTableAdapter()) 6 { 7 prodottiAdapter.Fill(dsProdotti.Prodotti); 8 } 9 10 ReportViewer1.LocalReport.DataSources.Clear(); 11 ReportViewer1.LocalReport.DataSources.Add(new Microsoft.Reporting.WebForms.ReportDataSource("DsProdotti_Prodotti", dsProdotti.Prodotti));

 

Gestendo  l'evento RowChanged del DataTable Prodotti, possiamo popolare il valore del campo Immagine della riga aggiunta alla collezione del DataTable, con lo stream di byte rappresentante l'immagine che vogliamo visualizzare:

1 void Prodotti_RowChanged(object sender, DataRowChangeEventArgs e) 2 { 3 if (e.Action == DataRowAction.Add) 4 { 5 //Immagine da Stream 6 e.Row["Immagine"] = ImageDataRow.ImageDataRowIstance.GetImageArray(); 7 } 8 }

Dove il codice della classe ImageDataRow è il seguente:

1 public class ImageDataRow 2 { 3 private static byte[] _imageArray = null; 4 private static ImageDataRow _imageDataRowIstance; 5 6 private ImageDataRow() { } 7 8 public static ImageDataRow ImageDataRowIstance 9 { 10 get 11 { 12 if (_imageDataRowIstance == null) 13 _imageDataRowIstance = new ImageDataRow(); 14 return _imageDataRowIstance; 15 } 16 } 17 18 public System.Byte[] GetImageArray() 19 { 20 if (_imageArray == null) 21 { 22 using (MemoryStream imgStream = new MemoryStream()) 23 { 24 System.Drawing.Image img = new Bitmap(32, 32); 25 Graphics gr = Graphics.FromImage(img); 26 gr.FillRectangle(new SolidBrush(Color.White), 0, 0, 32, 32); 27 gr.DrawEllipse(new Pen(Color.Red, 2), 1, 1, 30, 30); 28 img.Save(imgStream, System.Drawing.Imaging.ImageFormat.Gif); 29 _imageArray = imgStream.ToArray(); 30 } 31 } 32 return _imageArray; 33 } 34 }

Dato che nell'esempio viene visualizzata sempre la stessa immagine, per non instanziare ad ogni riga un oggetto MemoryStream ed eseguire il codice di  disegno, si è scelto di utilizzare un Singleton. Ovviamente, nel caso in cui l'immagine debba cambiare a seconda dei valori contenuti nella riga, il codice dovrà essere ottimizzato opportunamente.

Il risultato che si otterrà eseguendo il codice, sarà qualcosa del tipo:

image

Sorgenti completi del progetto

posted @ martedì 25 novembre 2008 17.42 | Feedback (0) | Filed Under [ C# ASP.NET Reporting ]

giovedì 20 novembre 2008

Se vi annoiate, aiutate la scienza...

Leggevo un articolo su  una serie di attività e software che potrebbero aiutare la comunità scientifica, distraendosi e utilizzando una parte del tempo libero (e un pò mi viene da ridere...) con semplici videogiochi o con ad esempio, un software per la modellazione 3D di proteine, che aiuterebbe la ricerca contro il cancro e l'Aids. Sembra molto interessante, ma  bisogna vedere il numero di persone che aderirà ai vari progetti.

posted @ giovedì 20 novembre 2008 18.04 | Feedback (0) | Filed Under [ Varie ed eventuali ]

domenica 16 novembre 2008

Cartelle condivise con Sun VirtualBox

Post a titolo di promemoria. Per aggiungere una cartella condivisa in Sun VirtualBox e Microsoft Windows XP Pro come sistema guest, avviata la macchina virtuale, dalla barra dei menu: Dispositivi\Cartelle condivise... e nella finestra Cartelle condivise, premere su Add New Shared Folder...

image

Nella finestra visualizzata, specificare il percorso della cartella sulla macchina host da condividere nel campo Folder Path,  e specificare un nome (senza spazi) nel campo Folder Name (ad esempio Temp). A questo punto il gioco è quasi fatto. Nella macchina guest, da riga di comando digitare:

net use z: \\vboxsrv\Temp

dove z: è la lettera che si vuole assegnare all'unità di rete mappata sulla cartella condivisa.

posted @ domenica 16 novembre 2008 17.27 | Feedback (0) | Filed Under [ Virtual Machine ]

venerdì 14 novembre 2008

[OT] Se il vostro PC è brutto...

...qui potete trovare qualche idea per modificarlo :-)

posted @ venerdì 14 novembre 2008 8.34 | Feedback (0) | Filed Under [ OT ]

giovedì 6 novembre 2008

WPF: Control Template

In WPF, l'aspetto grafico di un controllo può essere cambiato utilizzando un Control Template, ovvero un'insieme di risorse, triggers ed elementi che descrivono il comportamento grafico del controllo. I Control Template sono utili ogni qual volta si vuole modificare l'aspetto grafico di un controllo, ma allo stesso tempo conservare le funzionalità del controllo stesso. Senza WPF, magari saremmo costretti a costruire un nuovo controllo replicando funzionalità e riscrivendo del codice funzionante. Supponiamo ad esempio di voler cambiare l'aspetto del solito controllo Button, rendendolo fashion e trendy. Quello che vogliamo ottenere è qualcosa del tipo:

 image image

Nella seconda figura, è mostrato il comportamento del controllo Button quando il cursorse del mouse è posizionato sopra.

Uno dei metodi più semplici per cambiare il Template del controllo è quello di scrivere il codice XAML di descrizione direttamente all'interno del tag Button.Template, ad esempio:

1 <Button Height="16" Margin="51,0,42,12" Name="button2" VerticalAlignment="Bottom" Content="Bottone"> 2 <Button.Template > 3 <ControlTemplate> 4 <Grid> 5 <!-- codice XAML --> 6 </Grid> 7 </ControlTemplate> 8 </Button.Template > 9 </Button>

Volendo cambiare l'aspetto di tutti i controlli Button presenti in una Form WPF, andiamo ad utilizzare un oggetto Style, aggiungendolo  alla collezione delle risorse della Window WPF su cui stiamo lavorando:

1 <Window.Resources> 2 <Style TargetType="Button"> 3 <Setter Property="Template"> 4 ... 5 </Setter> 6 </Style> 7 </Window.Resources> 8

Utilizzando una classe Setter, andiamo ad impostare la proprietà Template del generico controllo Button, aggiungendo in cascata, una Grid, un Border ed un Rectangle.

1 <Grid> 2 <Border BorderBrush="Aquamarine" BorderThickness="1" Name="borderButton"> 3 <Rectangle Name="sfondo"> 4 <Rectangle.Fill> 5 <LinearGradientBrush StartPoint="0,0" EndPoint="1,0" Opacity="1"> 6 ... 7 </LinearGradientBrush> 8 </Rectangle.Fill> 9 </Rectangle> 10 </Border> 11 <ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center" /> 12 </Grid>

E' importante spendere qualche parola su ContentPresenter. ContentPresenter serve a visualizzare il contenuto (in questo caso la semplice stringa "Button") di un ContentControl come ad esempio Frame, ToolTip, Label, GroupItem,ButtonBase etc...Se non utilizzassimo ContentPresenter durante la definizione del Template del nostro Button, in fase di Rendering, non verrebbe visualizzata nessuna dicitura sul nostro Button, semplicemente perchè non abbiamo detto a WPF dove vogliamo visualizzarla. Possiamo vedere il ContentPresenter come un segnaposto per indicare dove visualizzare il Content. Utilizzando una Grid, come in questo caso, ci assicuriamo che i vari oggetti siano tutti visualizzati in un'unica cella della griglia. Impostando HorizontalAlignment e VerticalAlignment su Center, ci assicuriamo di visualizzare il contenuto del controllo al centro.

Per cambiare il Background del Button quando il cursorse del mouse viene posizionato sopra la superficie del controllo, come per Style, anche per ControlTemplate abbiamo a disposizione  i Triggers da sfruttare:

1 <ControlTemplate.Triggers> 2 <Trigger Property="IsMouseOver" Value="true"> 3 <Setter TargetName="sfondo" Property="Fill" > 4 <Setter.Value> 5 <LinearGradientBrush StartPoint="0,0" EndPoint="1,0" Opacity="0.8"> 6 ... 7 </LinearGradientBrush> 8 </Setter.Value> 9 </Setter> 10 </Trigger> 11 </ControlTemplate.Triggers>

Molto semplicemente, quando ci troviamo con il cursore del mouse sul Button, il Trigger cambia "il valore" (in verità l'oggetto LinearGradientBrush) della proprietà Fill dell'oggetto che ha la proprietà Name impostata su Sfondo. Nel procedente codice XAML, questo è Rectangle, posto all'interno dell'oggetto Border , di nome borderButton.

Fino  a questo punto, abbiamo raggiunto il nostro primo obiettivo.  Supponiamo ora di voler aggiungere un'ulteriore funzione grafica al nostro controllo. Supponiamo di voler aggiungere un effetto luce diffusa (Glow), quando ci troviamo ad indicare il button con il mouse (sfruttando in pratica lo stesso Trigger per IsMouseOver). A questo punto, niente di più facile, dato che l'oggetto Border espone una proprietà BitmapEffect. Scrivendo del codice XAML simile a questo:

1 <Setter TargetName="borderButton" Property="BitmapEffect"> 2 <Setter.Value > 3 <OuterGlowBitmapEffect GlowColor="Yellow" GlowSize="10" /> 4 </Setter.Value> 5 </Setter>

Otterremo l'effetto desiderato:

image

Personalmente penso che le potenzialità che il WPF offre per personalizzare l'aspetto dei controll sia veramente impressionante. Utilizzando Expression Blend si possono sviluppare delle applicazioni davvero accattivanti (soprattutto se si ha un pò di dimestichezza con la grafica :-))

Codice XAML completo della Window WPF

Technorati Tag: ,

posted @ giovedì 6 novembre 2008 13.05 | Feedback (0) | Filed Under [ WPF ]

lunedì 3 novembre 2008

Icone gratis

Come segnalato da Repubblica, sul sito Six Revisions è possibile scaricare 40 Beatiful Free Icon Sets nei formati png e ico.

Technorati Tag:

posted @ lunedì 3 novembre 2008 17.45 | Feedback (0) | Filed Under [ Varie ed eventuali ]

Da Microsoft Virtual PC a Sun VirtualBox

Avevo la necessità di convertire una macchina virtuale da formato Microsoft Virtual PC a Sun VirtualBox. Per chi avesse avuto lo stesso problema, la soluzione è stata abbastanza semplice: ho eseguito il download di VMware Converter 3.0.3 (Starter Edition) (previa registrazione),  una volta installato è stato sufficiente lanciare il Wizard avviabile da: File\New\Convert:

image

e seguire i vari passi:

image

Impostando come Source Type: Other ed  in Virtual Machine il percorso del file con estensione *.vmc. Scegliendo Avanti, il converter inizierà a leggere le informazioni del file della macchina virtuale di Microsoft Virtural PC  (Ci metterà qualche minuto).

Proseguendo con il Wizard (dove è possibile ad esempio eseguire la conversione mantenendo la dimensione del disco fissa oppure ridimensionandolo per salvare spazio disco), al momento di scegliere il tipo di destinazione (Select the destination type), ho selezionato Other Virtual Machine, e nella schermata successiva, ho specificato il nome della Virtual Machine  e ho selezionato Workstation 6.x, VMware Fusion 1.x, Player 2.x, ACE 2.x. Andando avanti si possono scegliere altre opzioni secondo delle proprie esigenze. Secondo della dimensione del file della Virtual Machine di cui si vuol fare la conversione, la procedura richiederà un pò di tempo (nel mio caso per una file di circa 19GB sono stati necessari più di 30 minuti).

A questo punto non resta che creare una nuova macchina virtuale su Sun VirtualBox seguendo il Wizard. Al momento della scelta dell'Hard-disk virtuale, scegliere esistente:

image

nel Gestore dei dischi virtuali, fare click su aggiungi e scegliere il percorso del file con estensione *.vmdk creato utilizzando il VMWare converter.

image

Una volta selezionato il file, è sufficiente continuare fino alla fine. Una volta terminata la procedura guidata è possibile impostare le varie opzioni per la macchina virtuale appena creata (attivare l'accesso a periferiche USB, impostare le schede di rete, cartelle condivise etc...).

Al momento, l'unico problema che ho incontrato dopo la conversione è un leggero sfarfallio del contenuto della finestra della macchina virtuale durante il passaggio della modalità a Schermo intero e viceversa o durante il ridimensionamento della finestra del sistema guest, tutto sommato nulla di particolare. Non resta che testare il comportamento durante le sessioni di lavoro.

posted @ lunedì 3 novembre 2008 17.30 | Feedback (2) | Filed Under [ Virtual Machine ]

domenica 2 novembre 2008

FTP: Download/Upload di un file con ProgressBar

Post nato da discussione su forum. Supponiamo di voler creare un client ftp (applicazione Windows Form) per il download/upload di file, utilizzando un controllo ProgressBar per visualizzare lo stato di avanzamento dell'operazione. Grazie alle classi messe a disposizione del Framework .Net, il codice per il download di un file remoto, potrebbe essere del tipo:

1 //Connessione con l'host 2 Connect(remotePathFile); 3 4 //Imposta il tipo di richiesta 5 _conn.Method = WebRequestMethods.Ftp.DownloadFile; 6 7 //Ottiene la risposta 8 _resp = (FtpWebResponse)(_conn.GetResponse()); 9 System.IO.Stream _respStream = _resp.GetResponseStream(); 10 11 if (ContinueProcess(_resp.StatusDescription)) 12 { 13 //Apre il file locale per la scrittura 14 //.... 15 16 try 17 { 18 //Recupera la dimensione del file come numero di bytes 19 Int64 totalBytes = GetFileSize(remotePathFile); 20 Int64 totalBytesRead = 0; 21 22 if (downloadFileStarted != null) downloadFileStarted(totalBytes); 23 24 byte[] buf = new byte[1024]; 25 26 int bytesRead = _respStream.Read(buf, 0, buf.Length); 27 28 while (bytesRead != 0) 29 { 30 totalBytesRead += bytesRead; 31 32 if (downloadFileProgress != null) downloadFileProgress(totalBytes, totalBytesRead); 33 34 fileStream.Write(buf, 0, bytesRead); 35 36 bytesRead = _respStream.Read(buf, 0, buf.Length); 37 } 38 39 if (downloadFileCompleted != null) downloadFileCompleted(); 40 41 return true; 42 } 43 catch (WebException ex) 44 { 45 //..... 46 } 47 finally 48 { 49 fileStream.Close(); 50 _respStream.Close(); 51 } 52 } 53 else ... 54 }

mentre il codice per eseguire l'upload, potrebbe essere del tipo:

1 if (Connect(remoteFilePath)) 2 { 3 try 4 { 5 //Connected 6 _conn.Method = WebRequestMethods.Ftp.UploadFile; 7 8 FileInfo file = new FileInfo(localFilePath); 9 10 if (file.Length > 0) 11 { 12 if (uploadFileStarted != null) uploadFileStarted(file.Length); 13 14 Stream strUpload = _conn.GetRequestStream(); 15 16 int bytesRead = 0; 17 int totalBytesRead = 0; 18 byte[] fileBytes = new byte[1024]; 19 20 FileStream strLocalFile = new FileStream(localFilePath, FileMode.Open); 21 bytesRead = strLocalFile.Read(fileBytes, 0, fileBytes.Length); 22 23 while (bytesRead != 0) 24 { 25 totalBytesRead += bytesRead; 26 27 strUpload.Write(fileBytes, 0, bytesRead); 28 29 if (uploadFileProgress != null) uploadFileProgress(file.Length, totalBytesRead); 30 31 bytesRead = strLocalFile.Read(fileBytes, 0, fileBytes.Length); 32 } 33 34 strLocalFile.Close(); 35 strUpload.Close(); 36 37 if (uploadFileCompleted != null) uploadFileCompleted(); 38 } 39 } 40 catch (WebException ex) {...} 41 catch (Exception ex) { ...} 42 } 43 else{...}

Nulla di particolare, tranne che, sia per l'upload che per il download, il file viene inviato/scaricato un blocco per volta, nell'esempio di dimensione massima di 1024 Byte.

In allegato, un'applicazione Windows Form molto semplice.

image

Le operazioni di download/upload sono eseguite su un thread diverso da quello prin