J'ai besoin de diffuser un fichier qui entraînera une sauvegarde en tant qu'invite dans le navigateur. Le problème est que le répertoire dans lequel se trouve le fichier est virtuellement mappé. Je ne peux donc pas utiliser Server.MapPath pour déterminer son emplacement réel. Le répertoire ne se trouve pas au même emplacement (ni même sur les serveurs physiques des boîtiers actifs) que le site Web.
Je voudrais quelque chose comme ce qui suit, mais cela me permettra de transmettre une URL Web, et non un chemin de fichier du serveur.
Je vais peut-être devoir créer mon chemin de fichier à partir d'un chemin de base de configuration, puis l'ajouter au reste du chemin, mais j'espère pouvoir le faire de cette façon.
var filePath = Server.MapPath(DOCUMENT_PATH);
if (!File.Exists(filePath))
return;
var fileInfo = new System.IO.FileInfo(filePath);
Response.ContentType = "application/octet-stream";
Response.AddHeader("Content-Disposition", String.Format("attachment;filename=\"{0}\"", filePath));
Response.AddHeader("Content-Length", fileInfo.Length.ToString());
Response.WriteFile(filePath);
Response.End();
Vous pouvez utiliser HttpWebRequest pour obtenir le fichier et le retransmettre au client. Cela vous permet d’obtenir le fichier avec une URL. Un exemple de ceci que j'ai trouvé (mais ne me souviens pas où donner du crédit) est
//Create a stream for the file
Stream stream = null;
//This controls how many bytes to read at a time and send to the client
int bytesToRead = 10000;
// Buffer to read bytes in chunk size specified above
byte[] buffer = new Byte[bytesToRead];
// The number of bytes read
try
{
//Create a WebRequest to get the file
HttpWebRequest fileReq = (HttpWebRequest) HttpWebRequest.Create(url);
//Create a response for this request
HttpWebResponse fileResp = (HttpWebResponse) fileReq.GetResponse();
if (fileReq.ContentLength > 0)
fileResp.ContentLength = fileReq.ContentLength;
//Get the Stream returned from the response
stream = fileResp.GetResponseStream();
// prepare the response to the client. resp is the client Response
var resp = HttpContext.Current.Response;
//Indicate the type of data being sent
resp.ContentType = "application/octet-stream";
//Name the file
resp.AddHeader("Content-Disposition", "attachment; filename=\"" + fileName + "\"");
resp.AddHeader("Content-Length", fileResp.ContentLength.ToString());
int length;
do
{
// Verify that the client is connected.
if (resp.IsClientConnected)
{
// Read data into the buffer.
length = stream.Read(buffer, 0, bytesToRead);
// and write it out to the response's output stream
resp.OutputStream.Write(buffer, 0, length);
// Flush the data
resp.Flush();
//Clear the buffer
buffer = new Byte[bytesToRead];
}
else
{
// cancel the download if client has disconnected
length = -1;
}
} while (length > 0); //Repeat until no data is read
}
finally
{
if (stream != null)
{
//Close the input stream
stream.Close();
}
}
Téléchargez l'URL en octets et convertissez-les en flux:
using (var client = new WebClient())
{
var content = client.DownloadData(url);
using (var stream = new MemoryStream(content))
{
...
}
}
Je fais cela un peu et je pensais pouvoir ajouter une réponse plus simple. Je l’organise comme une simple classe ici, mais j’utilise cette technique tous les soirs pour collecter des données financières sur les entreprises que je suis.
class WebPage
{
public static string Get(string uri)
{
string results = "N/A";
try
{
HttpWebRequest req = (HttpWebRequest)WebRequest.Create(uri);
HttpWebResponse resp = (HttpWebResponse)req.GetResponse();
StreamReader sr = new StreamReader(resp.GetResponseStream());
results = sr.ReadToEnd();
sr.Close();
}
catch (Exception ex)
{
results = ex.Message;
}
return results;
}
}
Dans ce cas, je passe dans une URL et la page est renvoyée au format HTML. Si vous voulez faire quelque chose de différent avec le flux, vous pouvez facilement changer cela.
Vous l'utilisez comme ceci:
string page = WebPage.Get("http://finance.yahoo.com/q?s=yhoo");
Deux ans plus tard, j'utilisais la réponse de Dallas, mais je devais changer le HttpWebRequest
en FileWebRequest
puisque je liais vers des fichiers directs. Pas sûr que ce soit le cas partout, mais je me suis dit que je l'ajouterais. Aussi, j'ai enlevé
var resp = Http.Current.Resonse
et juste utilisé Http.Current.Response
_ en place partout où resp
a été référencé.
La solution acceptée par Dallas fonctionnait pour nous si nous utilisions Load Balancer sur Citrix Netscaler (sans stratégie WAF).
Le téléchargement du fichier ne fonctionne pas via le LB de Netscaler quand il est associé à WAF car le scénario actuel (Content-length n’est pas correct) est une violation RFC et AppFW réinitialise la connexion, ce qui n’est pas le cas lorsque WAF la politique n'est pas associée.
Donc ce qui manquait était:
Response.End ();
Voir aussi: Essayer de diffuser un PDF avec asp.net génère un "fichier endommagé"