<?xml version="1.0" encoding="UTF-8" ?>
<?xml-stylesheet type="text/xsl" href="http://www.aspnetzone.de/utility/FeedStylesheets/rss.xsl" media="screen"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:wfw="http://wellformedweb.org/CommentAPI/"><channel><title>Search results matching tags 'asp.net', 'SQL Server', and 'Download'</title><link>http://www.aspnetzone.de/search/SearchResults.aspx?o=DateDescending&amp;tag=asp.net,SQL+Server,Download&amp;orTags=0</link><description>Search results matching tags 'asp.net', 'SQL Server', and 'Download'</description><dc:language>en-US</dc:language><generator>CommunityServer 2.1 SP2 (Build: 61120.2)</generator><item><title>Gro&amp;#223;e Dateien aus einer Datenbank lesen und zum Download bereitstellen.</title><link>http://www.aspnetzone.de/blogs/juergengutsch/archive/2008/11/22/gro-e-dateien-aus-einer-datenbank-lesen-und-zum-download-bereitstellen.aspx</link><pubDate>Sat, 22 Nov 2008 08:45:00 GMT</pubDate><guid isPermaLink="false">ce930855-ae9b-4fa4-8077-06a76071cc6a:204248</guid><dc:creator>Jürgen Gutsch</dc:creator><description>&lt;P&gt;in dem Beitrag "Große Dateien in hochladen und in eine Datenbank schreiben" habe ich beschrieben, wie man Dateien performant in die Datenbank schreiben kann. Umgekehrt sollten die Werte ja auch wieder ausgelesen werden. Auch hier gibt es in der MSDN wieder einen Artikel dazu: &lt;A title="Abrufen von BLOB-Werten aus einer Datenbank" href="http://msdn.microsoft.com/de-de/library/aa720355.aspx"&gt;Abrufen von BLOB-Werten aus einer Datenbank&lt;/A&gt; &lt;/P&gt;
&lt;P&gt;Unten habe ich ein Beispielprojekt verlinkt in dem gezeigt wird, wie die vom Microsoft beschriebene Methode in einer ASP.NET Anwendung genutzt werden kann, um Dateien aus der Datenbank auszulesen und über einen HttpHandler zum Download bereit zu stellen.&lt;/P&gt;
&lt;P&gt;&lt;/P&gt;
&lt;P&gt;Das Auslesen der Daten ist im Vergleich zum schreiben wesentlich einfacher und mit reinen ADO.NET Möglichkeiten umzusetzen. Der Trick hierbei ist, dass man dem DataReader (mit Hilfe des &lt;A title=CommandBehavior-Enumeration href="http://msdn.microsoft.com/de-de/library/system.data.commandbehavior.aspx"&gt;CommandBehaviors&lt;/A&gt;&amp;nbsp; "SequentialAccess") sagen kann, dass er die Daten nicht komplett aus der Datenbank laden soll, sondern als Stream:&lt;/P&gt;
&lt;P&gt;SqlDataReader myReader = comd.ExecuteReader(CommandBehavior.SequentialAccess);&lt;/P&gt;
&lt;P&gt;Anschließend könne die Binärdaten mit GetBytes() stückchenweise über den DataReader aus der Datenbank ausgelesen werden:&lt;/P&gt;
&lt;P&gt;&lt;code&gt;&lt;span style="color: Black;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;&lt;span style="color: Blue;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;int&lt;/span&gt; bufferLen &lt;span style="color: Red;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;=&lt;/span&gt; 1024;  &lt;br /&gt;&lt;span style="color: Blue;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;byte&lt;/span&gt;[] buffer &lt;span style="color: Red;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;=&lt;/span&gt; &lt;span style="color: Blue;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;new&lt;/span&gt; &lt;span style="color: Blue;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;byte&lt;/span&gt;[bufferLen]; &lt;br /&gt;&lt;span style="color: Blue;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;long&lt;/span&gt; retval; &lt;br /&gt;&lt;span style="color: Blue;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;long&lt;/span&gt; offset &lt;span style="color: Red;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;=&lt;/span&gt; 0; &lt;br /&gt;[...] &lt;br /&gt;&lt;span style="color: Blue;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;if&lt;/span&gt; (myReader.Read()) &lt;br /&gt;{ &lt;br /&gt;    &lt;span style="color: Blue;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;using&lt;/span&gt; (BinaryWriter bw &lt;span style="color: Red;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;=&lt;/span&gt; &lt;span style="color: Blue;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;new&lt;/span&gt; BinaryWriter(OutputStream)) &lt;br /&gt;    { &lt;br /&gt;        retval &lt;span style="color: Red;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;=&lt;/span&gt; myReader.GetBytes(0, offset, buffer, 0, bufferLen);  &lt;br /&gt;        &lt;span style="color: Blue;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;while&lt;/span&gt; (retval == bufferLen) &lt;br /&gt;        { &lt;br /&gt;            bw.Write(buffer); &lt;br /&gt;            bw.Flush();  &lt;br /&gt;            offset += bufferLen; &lt;br /&gt;            retval &lt;span style="color: Red;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;=&lt;/span&gt; myReader.GetBytes(0, offset, buffer, 0, bufferLen); &lt;br /&gt;        }  &lt;br /&gt;        bw.Write(buffer, 0, (&lt;span style="color: Blue;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;int&lt;/span&gt;)retval &lt;span style="color: Red;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;-&lt;/span&gt; 1); &lt;br /&gt;        bw.Flush(); &lt;br /&gt;        bw.Close(); &lt;br /&gt;    } &lt;br /&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/P&gt;
&lt;P&gt;Auch hier bestimmt die Puffergröße (bufferLen) nicht nur Größe der Datenpakete, sondern auch die Anzahl der Schleifendurchläufe. Ein niedriger Wert erhöht die Schleifendurchläufe reduziert den Speicherbedarf, erhöht aber die Prozessorlast. Umgekehrt verringert ein höherer Wert die Prozessorlast, erhöht aber den Speicherbedarf. Man sollte also mit der Größe spielen um den perfekten Mittelwert zu finden.&lt;/P&gt;
&lt;P&gt;Genauso wie in dem vorhergehenden Artikel aus dem vorhandenen Stream partiell gelesen wird, wird hier Stück für Stück in einen Steam geschrieben. Der Stream kann dann der aktuelle OutpuStream eines generischen HttpHandlers sein. Die ProzessRequest Methode des generischen HttpHandlers könnte dann wie folgt aussehen:&lt;/P&gt;
&lt;P&gt;&lt;code&gt;&lt;span style="color: Black;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt; &lt;br /&gt;&lt;br /&gt;&lt;span style="color: Blue;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;public&lt;/span&gt; &lt;span style="color: Blue;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;void&lt;/span&gt; ProcessRequest(HttpContext context) &lt;br /&gt;{ &lt;br /&gt;    &lt;span style="color: Blue;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;int&lt;/span&gt; id &lt;span style="color: Red;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;=&lt;/span&gt; 0; &lt;br /&gt;    &lt;span style="color: Blue;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;if&lt;/span&gt; (!&lt;span style="color: Blue;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;int&lt;/span&gt;.TryParse(context.Request.QueryString[id], &lt;span style="color: Blue;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;out&lt;/span&gt; id)) &lt;br /&gt;        &lt;span style="color: Blue;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;return&lt;/span&gt;;  &lt;br /&gt;    MyFile file &lt;span style="color: Red;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;=&lt;/span&gt; BinaryManager.ReadFile(id); &lt;br /&gt;    &lt;span style="color: Blue;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;if&lt;/span&gt; (file == &lt;span style="color: Blue;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;null&lt;/span&gt;) &lt;br /&gt;        &lt;span style="color: Blue;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;return&lt;/span&gt;;  &lt;br /&gt;    context.Response.ContentType &lt;span style="color: Red;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;=&lt;/span&gt; file.ContentType; &lt;br /&gt;    context.Response.AddHeader(&lt;span style="color: #666666;background-color: #e4e4e4;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;"Content-Disposition"&lt;/span&gt;, &lt;br /&gt;        &lt;span style="color: #666666;background-color: #e4e4e4;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;"attachment; filename="&lt;/span&gt; &lt;span style="color: Red;background-color: Transparent;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;+&lt;/span&gt; &lt;br /&gt;        System.IO.Path.GetFileName(file.FileName)); &lt;br /&gt;    context.Response.AddHeader(&lt;span style="color: #666666;background-color: #e4e4e4;font-family: Courier New;font-size: 14px;font-weight: normal;"&gt;"Content-Length"&lt;/span&gt;, file.FileSize.ToString());  &lt;br /&gt;    BinaryManager.ReadFromDB(context.Response.OutputStream, id); &lt;br /&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/P&gt;
&lt;P&gt;Übrigenz macht es Sinn jede große Datei, egal ob sie aus der Datenbank kommt oder nicht, in so einer Schleife, stückchenweise in den ResponseStream zu schreiben. Der Browser muss auf diese Art nicht zu lange auf eine erste Reaktion vom Webserver warten. Der Download funktioniert dan schneller und flüssiger.&lt;/P&gt;
&lt;P&gt;Beispielprojekt: &lt;A href="http://www.aspnetzone.de/files/folders/204249/download.aspx"&gt;download&lt;/A&gt; (228KB)&lt;/P&gt;</description></item></channel></rss>