OVH Cloud OVH Cloud

Upload avec IIS : Fichier fermé

23 réponses
Avatar
David
Bonjour,

J'ai un bout de code qui me permet de faire de l'upload avec un composant
upload ASP.Net.
Le code fonctionne très bien avec le serveur interne de VS.Net 2005, par
contre avec IIS 5 il me génère un IODisposedObject lorsque j'essaye de lire
le fichier source.

Voici le code :
// Flux d'écriture du fichier sur le serveur
FileStream fs = new FileStream(this.p_filesNames[i],
FileMode.OpenOrCreate);

// Flux de lecture du fichier
BinaryReader br = new BinaryReader(file.InputStream);

try
{
// Tant qu'on a pas tout lu et qu'on ne doit pas stopper
while (br.BaseStream.Length - br.BaseStream.Position > 0 &&
!this.p_stopUpload)
{

// S'il y a moins d'octet a récupérér que la taille du tampon
if (br.BaseStream.Length - br.BaseStream.Position < bufferSize)
{
bufferSize = (int)(br.BaseStream.Length -
br.BaseStream.Position);
}

br.Read(buffer, 0, bufferSize); // lecture => il plante ici
!!!!!
fs.Write(buffer, 0, bufferSize); // écriture
this.p_totalUploaded += bufferSize;
this.p_partialUploaded = br.BaseStream.Position;
}
}
finally
{
// Fermeture des flux
br.Close();
fs.Close();
}

Et je peux vous assurer que le fichier que je veux uploader n'est pas ouvert
ou utilisé par quelque chose.
Par contre, j'ai remarqué que ça fonctionne pour des fichier < 64 Ko !!
Encore une fois, pour des gros fichiers, ça fonctionne avec le petit serveur
interne.
Quelle est dans IIS l'option qui déconne ?

Merci pour votre aide.

3 réponses

1 2 3
Avatar
En effet, c'est quelque chose de ce gout.
Je rappelle le déroulement :
- je suis dans ma WebForm, je valide mon formulaire et dans le code .cs,
j'appelle le constructeur d'une classe Uploading en lui passant en paramètre
Request.Files
- J'arrive dans le constructeur (tout va bien, je récupère mon
HttpFileCollection)
- Je lance un thread qui fait le traitement sur mes fichiers (il utilise une
variable privée à ma classe pour récupérer les fichiers)
- A ce moment, le serveur quitte le code de ma webform appelante

L'objet Request est libéré ainsi que les fichiers !

Du coup, comment "bloquer" la request de ma webform en attendant le
déroulement de mon thread.

La finalité :
Avoir un thread d'upload qui renvoi les infos du traitement (taille
émis/restant, ...) via un système de call back en Ajax à ma page principale.
Tout le mécanisme fonctionne bien...
Ce que je crains c'est que :
- Si je bloque le request de ma webform (par je ne sais quel moyen), je ne
pourrais plus aller dans ma page principale (le système sera en attente)
- Si je ne bloque pas la request, je perd mes fichiers...

Alors je pense être dans une impasse !
Mais ce n'est donc pas possible ce que je veux faire ????

Mais alors pourquoi ça fonctionne bien en asp.net 1.1 et en asp.net 2.0 avec
le serveur interne ?
A croire que la Request n'est pas tout de suite libérée tant qu'on veut
l'utiliser ??
Il n'y a pas des options du garbage collector ?

Une autre solution ?
Pour info, je suis sous IIS 5 (Win XP SP2)

Merci.
--
David


"Patrice" <http://www.chez.com/scribe/> a écrit dans le message de news:

Objectif de l'utilisation d'un thread ? A mon avis, le thread continue à
s'exécuter alors que la requête HTTP est déjà finie (bloques tu la requête
en attente de la fin de ce thread ?) donc les données téléchargées (les
fichiers) deviennent indisponibles pendant l'exécution de ce thread.

--
Patrice

"David" a écrit dans le message de news:

En fait, je viens de faire des tests :
Si j'exécute le code directement sur le OnClick d'un bouton, ça
fonctionne
nickel même avec IIS !
Par contre, dans mon cas, je lance le traitement dans un thread.
Et apparemment, c'est de là que vient le pb.

En fait, je récupère la liste des fichiers dans un HttpFileCollection.
J'instancie une classe (Uploading) en lui mettant cette liste de fichiers
en
paramètre.
Si j'exécute directement dans le constructeur de ma classe, ça fonctionne
bien.

Par contre, dans mon constructeur :
- J'instancie une variable global (p_files) de type HttpFileCollection,
en
mettant p_Files = Files (paramètre reçu dans ma classe)
- je lance un thread (sans paramètre).
Ce thread démarre et exploite la variable globale p_files.

Voici en gros le code de mon constructeur :
public Uploading(HttpFileCollection files, ...)
{
this.p_files = files;
// Création et lancement du thread
Thread upThread = new Thread(new ThreadStart(GetData));
upThread.Start();
}

Le code précédent se trouve dans GetData.

Dans mon cas, c'est bel et bien la variable p_files qui poserait pb car
le
f_files[0].InputStream ne peut pas être lu.
Est-ce que je m'y prend mal pour créer mon thread et dans la gestion des
variables ?

Merci...
--
David

"David" a écrit :

Pour info, je suis seul à utiliser le site (en dev actuellement) et je
suis
donc en local également.



"Gilles TOURREAU" a écrit :

> Le Fri, 22 Jun 2007 20:00:41 +0200, Gilles TOURREAU
> a écrit:
>
> > Le Fri, 22 Jun 2007 18:23:05 +0200, David
> > a écrit:
> >
> >> En fait, je boucle sur plusieurs fichiers à uploader :
> >> HttpFileCollection p_files = Request.Files;
> >> for (int i = 0; i < this.p_files.Count; i++)
> >> {
> >> HttpPostedFile file = this.p_files[i];
> >> ... Le code vu plus bas ...
> >> }
> >>
> >> --
> >> David
> >>
> >> "Gilles TOURREAU" a écrit :
> >>
> >>> Le Fri, 22 Jun 2007 17:39:03 +0200, David
> >>> a écrit:
> >>>
> >>> > Bonjour,
> >>> >
> >>> > J'ai un bout de code qui me permet de faire de l'upload avec un
> >>> composant
> >>> > upload ASP.Net.
> >>> > Le code fonctionne très bien avec le serveur interne de VS.Net
> >>> > 2005,
> >>> par
> >>> > contre avec IIS 5 il me génère un IODisposedObject lorsque
> >>> > j'essaye
> >>> de
> >>> > lire
> >>> > le fichier source.
> >>> >
> >>> > Voici le code :
> >>> > // Flux d'écriture du fichier sur le serveur
> >>> > FileStream fs = new FileStream(this.p_filesNames[i],
> >>> > FileMode.OpenOrCreate);
> >>> >
> >>> > // Flux de lecture du fichier
> >>> > BinaryReader br = new BinaryReader(file.InputStream);
> >>> > try
> >>> > {
> >>> > // Tant qu'on a pas tout lu et qu'on ne doit pas
> >>> > stopper
> >>> > while (br.BaseStream.Length - br.BaseStream.Position
> >>> > > 0
> >>> &&
> >>> > !this.p_stopUpload)
> >>> > {
> >>> >
> >>> > // S'il y a moins d'octet a récupérér que la
> >>> > taille du
> >>> > tampon
> >>> > if (br.BaseStream.Length - br.BaseStream.Position
> >>> > <
> >>> > bufferSize)
> >>> > {
> >>> > bufferSize = (int)(br.BaseStream.Length -
> >>> > br.BaseStream.Position);
> >>> > }
> >>> >
> >>> > br.Read(buffer, 0, bufferSize); // lecture => il
> >>> plante ici
> >>> > !!!!!
> >>> > fs.Write(buffer, 0, bufferSize); // écriture
> >>> > this.p_totalUploaded += bufferSize;
> >>> > this.p_partialUploaded = br.BaseStream.Position;
> >>> > }
> >>> > }
> >>> > finally
> >>> > {
> >>> > // Fermeture des flux
> >>> > br.Close();
> >>> > fs.Close();
> >>> > }
> >>> >
> >>> > Et je peux vous assurer que le fichier que je veux uploader
> >>> > n'est pas
> >>> > ouvert
> >>> > ou utilisé par quelque chose.
> >>> > Par contre, j'ai remarqué que ça fonctionne pour des fichier <
> >>> > 64 Ko
> >>> !!
> >>> > Encore une fois, pour des gros fichiers, ça fonctionne avec le
> >>> > petit
> >>> > serveur
> >>> > interne.
> >>> > Quelle est dans IIS l'option qui déconne ?
> >>> >
> >>> > Merci pour votre aide.
> >>>
> >>> Peux-tu poster le code concernant l'utilisation de la variable :
> >>> file
> >>>
> >>> Cordialement
> >>>
> >>> --
> >>> Gilles TOURREAU
> >>>
> >>>
> >>> S.A.R.L. P.O.S
> >>> Le spécialiste en motoculture depuis + de 30 ans !
> >>> http://www.pos.fr
> >>>
> >
> > Je vois pas où il y aurait un problème...
> > Cette exception est déclenché uniquement dans le cas ou vous appelez
> > la
> > méthode Close() ou Dispose() du BinaryReader et après un Read().
> >
> > Essayez cependant cette solution qui est bien meilleur que le
> > try/finally :
> >
> > using (FileStream fs = new FileStream(this.p_filesNames[i],
> > FileMode.OpenOrCreate))
> > {
> > using (BinaryReader br = new BinaryReader(file.InputStream))
> > {
> > //... Le code
> >
> > //Inutile de faire un close à la fin des using, car la
> > méthode
> > Dispose est automatiquement libéré...
> > }
> > }
> >
> > Cordialement
> >
> >
>
> Je viens de remarquer un truc interessant sur un de mes sites ASP...
> Quand le site "plante" (evenement Application_Error déclenché dans
> Global.asax), .NET libère toutes les ressources de toutes les demandes
> en
> cours en appellant la méthode Dispose() de tous les objets...
>
> Peut-être un début de piste pour toi :
> - Est-ce que ton site internet sur le IIS est utilisé par plusieurs
> utilisateurs en même temps ?
> - Si c'est le cas, cela veut dire qu'au moment du plantage, .NET
> appelle
> la méthode Dispose() de ton file.InputStream....
>
> Cordialement
>
> --
> Gilles TOURREAU
>
>
> S.A.R.L. P.O.S
> Le spécialiste en motoculture depuis + de 30 ans !
> http://www.pos.fr
>








Avatar
Si je ne peux pas cloner les fichiers, comment "bloquer" la request de ma
webform en attendant le déroulement de mon thread ?

La finalité :
Avoir un thread d'upload qui renvoi les infos du traitement (taille
émis/restant, ...) via un système de call back en Ajax à ma page principale.
Tout le mécanisme fonctionne bien...
Ce que je crains c'est que :
- Si je bloque le request de ma webform (par je ne sais quel moyen), je ne
pourrais plus aller dans ma page principale (le système sera en attente)
- Si je ne bloque pas la request, je perd mes fichiers...

Alors je pense être dans une impasse !
Mais ce n'est donc pas possible ce que je veux faire ????

Mais alors pourquoi ça fonctionne bien en asp.net 1.1 et en asp.net 2.0 avec
le serveur interne ?
A croire que la Request n'est pas tout de suite libérée tant qu'on veut
l'utiliser ??
Il n'y a pas des options du garbage collector ?

Une autre solution ?
Pour info, je suis sous IIS 5 (Win XP SP2)

Merci.
--
David

"Gilles TOURREAU" a écrit dans le message de news:

Le Mon, 25 Jun 2007 19:03:02 +0200, David
a écrit:

En fait, même avec le SaveAs ça fait la même erreur.

J'ai eu confirmation par d'autres personnes que si mon fichier disparait,
c'est normal.
En gros, voici le déroulement :
- je suis dans ma WebForm, je valide mon formulaire et dans le code .cs,
j'appelle le constructeur d'une classe Uploading en lui passant en
paramètre
Request.Files
- J'arrive dans le constructeur (tout va bien, je récupère mon
HttpFileCollection)
- Je lance un thread qui fait le traitement sur mes fichiers (il utilise
une
variable provée à ma classe pour récupérer les fichiers)
- A ce moment, le serveur quitte le code de ma webform appelante

Ce qu'on me dit :
L'objet Request est alors disposé et les fichiers avec !!!
Du coup, je me retrouve dans mon thread sans fichier...

On m'a conseillé de faire un clone de mon HttpFileCollection juste avant
d'appeler mon thread.
Je suis Ok, mais comment ????
As-tu une idée ?
Merci.

--
David

"Gilles TOURREAU" a écrit :

Le Mon, 25 Jun 2007 14:42:02 +0200, David
a écrit:

Là je ne vois pas du tout où est ton problème...

As-tu essayé la méthode HttpPostedFile.SaveAs() ?

Cordialement

--
Gilles TOURREAU


S.A.R.L. P.O.S
Le spécialiste en motoculture depuis + de 30 ans !
http://www.pos.fr






Malheureusement, tu ne peux pas cloner les HttpPostedFile, ni la
collection...

Au fait, quelle version d'IIS utilises-tu ?

--
Gilles TOURREAU


S.A.R.L. P.O.S
Le spécialiste en motoculture depuis + de 30 ans !
http://www.pos.fr


Avatar
Patrice
Tun es sûr que cela marche ? Tu as testé avec un gros fichier et avec une
connexion autre que réseau local ? Je dirais que la collection Request.Files
ne peut être construite que lorsque l'upload est fini (de mémoire, on a le
nom du fichier 1 suivi de son contenu etc... donc pour savoir qu'il y a n
fichiers, il faut avoir uploadé le contenu des n-1 fichiers précédents).

Je crains qu'il ne soit nécessaire de prendre la main à un plus bas niveau.
Voir par exemple :
http://www.codeproject.com/aspnet/File_Upload_Progress_Bar.asp

--
Patrice


<David> a écrit dans le message de news:

En effet, c'est quelque chose de ce gout.
Je rappelle le déroulement :
- je suis dans ma WebForm, je valide mon formulaire et dans le code .cs,
j'appelle le constructeur d'une classe Uploading en lui passant en
paramètre
Request.Files
- J'arrive dans le constructeur (tout va bien, je récupère mon
HttpFileCollection)
- Je lance un thread qui fait le traitement sur mes fichiers (il utilise
une
variable privée à ma classe pour récupérer les fichiers)
- A ce moment, le serveur quitte le code de ma webform appelante

L'objet Request est libéré ainsi que les fichiers !

Du coup, comment "bloquer" la request de ma webform en attendant le
déroulement de mon thread.

La finalité :
Avoir un thread d'upload qui renvoi les infos du traitement (taille
émis/restant, ...) via un système de call back en Ajax à ma page
principale.
Tout le mécanisme fonctionne bien...
Ce que je crains c'est que :
- Si je bloque le request de ma webform (par je ne sais quel moyen), je ne
pourrais plus aller dans ma page principale (le système sera en attente)
- Si je ne bloque pas la request, je perd mes fichiers...

Alors je pense être dans une impasse !
Mais ce n'est donc pas possible ce que je veux faire ????

Mais alors pourquoi ça fonctionne bien en asp.net 1.1 et en asp.net 2.0
avec le serveur interne ?
A croire que la Request n'est pas tout de suite libérée tant qu'on veut
l'utiliser ??
Il n'y a pas des options du garbage collector ?

Une autre solution ?
Pour info, je suis sous IIS 5 (Win XP SP2)

Merci.
--
David


"Patrice" <http://www.chez.com/scribe/> a écrit dans le message de news:

Objectif de l'utilisation d'un thread ? A mon avis, le thread continue à
s'exécuter alors que la requête HTTP est déjà finie (bloques tu la
requête en attente de la fin de ce thread ?) donc les données
téléchargées (les fichiers) deviennent indisponibles pendant l'exécution
de ce thread.

--
Patrice

"David" a écrit dans le message de
news:
En fait, je viens de faire des tests :
Si j'exécute le code directement sur le OnClick d'un bouton, ça
fonctionne
nickel même avec IIS !
Par contre, dans mon cas, je lance le traitement dans un thread.
Et apparemment, c'est de là que vient le pb.

En fait, je récupère la liste des fichiers dans un HttpFileCollection.
J'instancie une classe (Uploading) en lui mettant cette liste de
fichiers en
paramètre.
Si j'exécute directement dans le constructeur de ma classe, ça
fonctionne
bien.

Par contre, dans mon constructeur :
- J'instancie une variable global (p_files) de type HttpFileCollection,
en
mettant p_Files = Files (paramètre reçu dans ma classe)
- je lance un thread (sans paramètre).
Ce thread démarre et exploite la variable globale p_files.

Voici en gros le code de mon constructeur :
public Uploading(HttpFileCollection files, ...)
{
this.p_files = files;
// Création et lancement du thread
Thread upThread = new Thread(new ThreadStart(GetData));
upThread.Start();
}

Le code précédent se trouve dans GetData.

Dans mon cas, c'est bel et bien la variable p_files qui poserait pb car
le
f_files[0].InputStream ne peut pas être lu.
Est-ce que je m'y prend mal pour créer mon thread et dans la gestion des
variables ?

Merci...
--
David

"David" a écrit :

Pour info, je suis seul à utiliser le site (en dev actuellement) et je
suis
donc en local également.



"Gilles TOURREAU" a écrit :

> Le Fri, 22 Jun 2007 20:00:41 +0200, Gilles TOURREAU
> a écrit:
>
> > Le Fri, 22 Jun 2007 18:23:05 +0200, David
> > a écrit:
> >
> >> En fait, je boucle sur plusieurs fichiers à uploader :
> >> HttpFileCollection p_files = Request.Files;
> >> for (int i = 0; i < this.p_files.Count; i++)
> >> {
> >> HttpPostedFile file = this.p_files[i];
> >> ... Le code vu plus bas ...
> >> }
> >>
> >> --
> >> David
> >>
> >> "Gilles TOURREAU" a écrit :
> >>
> >>> Le Fri, 22 Jun 2007 17:39:03 +0200, David
> >>> a écrit:
> >>>
> >>> > Bonjour,
> >>> >
> >>> > J'ai un bout de code qui me permet de faire de l'upload avec un
> >>> composant
> >>> > upload ASP.Net.
> >>> > Le code fonctionne très bien avec le serveur interne de VS.Net
> >>> > 2005,
> >>> par
> >>> > contre avec IIS 5 il me génère un IODisposedObject lorsque
> >>> > j'essaye
> >>> de
> >>> > lire
> >>> > le fichier source.
> >>> >
> >>> > Voici le code :
> >>> > // Flux d'écriture du fichier sur le serveur
> >>> > FileStream fs = new FileStream(this.p_filesNames[i],
> >>> > FileMode.OpenOrCreate);
> >>> >
> >>> > // Flux de lecture du fichier
> >>> > BinaryReader br = new BinaryReader(file.InputStream);
> >>> > try
> >>> > {
> >>> > // Tant qu'on a pas tout lu et qu'on ne doit pas
> >>> > stopper
> >>> > while (br.BaseStream.Length -
> >>> > br.BaseStream.Position > 0
> >>> &&
> >>> > !this.p_stopUpload)
> >>> > {
> >>> >
> >>> > // S'il y a moins d'octet a récupérér que la
> >>> > taille du
> >>> > tampon
> >>> > if (br.BaseStream.Length - br.BaseStream.Position
> >>> > <
> >>> > bufferSize)
> >>> > {
> >>> > bufferSize = (int)(br.BaseStream.Length -
> >>> > br.BaseStream.Position);
> >>> > }
> >>> >
> >>> > br.Read(buffer, 0, bufferSize); // lecture => il
> >>> plante ici
> >>> > !!!!!
> >>> > fs.Write(buffer, 0, bufferSize); // écriture
> >>> > this.p_totalUploaded += bufferSize;
> >>> > this.p_partialUploaded = br.BaseStream.Position;
> >>> > }
> >>> > }
> >>> > finally
> >>> > {
> >>> > // Fermeture des flux
> >>> > br.Close();
> >>> > fs.Close();
> >>> > }
> >>> >
> >>> > Et je peux vous assurer que le fichier que je veux uploader
> >>> > n'est pas
> >>> > ouvert
> >>> > ou utilisé par quelque chose.
> >>> > Par contre, j'ai remarqué que ça fonctionne pour des fichier <
> >>> > 64 Ko
> >>> !!
> >>> > Encore une fois, pour des gros fichiers, ça fonctionne avec le
> >>> > petit
> >>> > serveur
> >>> > interne.
> >>> > Quelle est dans IIS l'option qui déconne ?
> >>> >
> >>> > Merci pour votre aide.
> >>>
> >>> Peux-tu poster le code concernant l'utilisation de la variable :
> >>> file
> >>>
> >>> Cordialement
> >>>
> >>> --
> >>> Gilles TOURREAU
> >>>
> >>>
> >>> S.A.R.L. P.O.S
> >>> Le spécialiste en motoculture depuis + de 30 ans !
> >>> http://www.pos.fr
> >>>
> >
> > Je vois pas où il y aurait un problème...
> > Cette exception est déclenché uniquement dans le cas ou vous
> > appelez la
> > méthode Close() ou Dispose() du BinaryReader et après un Read().
> >
> > Essayez cependant cette solution qui est bien meilleur que le
> > try/finally :
> >
> > using (FileStream fs = new FileStream(this.p_filesNames[i],
> > FileMode.OpenOrCreate))
> > {
> > using (BinaryReader br = new BinaryReader(file.InputStream))
> > {
> > //... Le code
> >
> > //Inutile de faire un close à la fin des using, car la
> > méthode
> > Dispose est automatiquement libéré...
> > }
> > }
> >
> > Cordialement
> >
> >
>
> Je viens de remarquer un truc interessant sur un de mes sites ASP...
> Quand le site "plante" (evenement Application_Error déclenché dans
> Global.asax), .NET libère toutes les ressources de toutes les
> demandes en
> cours en appellant la méthode Dispose() de tous les objets...
>
> Peut-être un début de piste pour toi :
> - Est-ce que ton site internet sur le IIS est utilisé par plusieurs
> utilisateurs en même temps ?
> - Si c'est le cas, cela veut dire qu'au moment du plantage, .NET
> appelle
> la méthode Dispose() de ton file.InputStream....
>
> Cordialement
>
> --
> Gilles TOURREAU
>
>
> S.A.R.L. P.O.S
> Le spécialiste en motoculture depuis + de 30 ans !
> http://www.pos.fr
>












1 2 3