Home arrow ASP.NET arrow Page 2 - HTTP File Download Without User Interaction Using .NET
ASP.NET

HTTP File Download Without User Interaction Using .NET


What can ASP.NET do for you? Well it may allow you to download a file from the server to the client in 8 lines. To find out more, read this article.

Author Info:
By: C. Prashanth
Rating: 4 stars4 stars4 stars4 stars4 stars / 238
April 28, 2003
TABLE OF CONTENTS:
  1. · HTTP File Download Without User Interaction Using .NET
  2. · The Article
  3. · Conclusion

print this article
SEARCH DEVARTICLES

HTTP File Download Without User Interaction Using .NET - The Article
(Page 2 of 3 )

The idea is to make the server read the contents of the file from its hard disk and write it into the Response stream of HTTP. A control or a component residing on the client machine must read the file from the Response stream and write it into the client's hard disk. Server implementation of the idea is very easy; with the help of ASP.NET we can do it in exactly 8 lines.

The difficult part is the client implementation, how do we make a piece of code execute on the client machine which is stored on the server. For this we look at some of the solutions provided by two software giants

1. Activex control - which is a Microsoft technology
2. Applet - which is a Sun technology
3. .NET client side control - which is also a Microsoft technology

The main disadvantage with writing a .NET client side custom control is that .NET framework must be installed on every client machine for it to work .We can't expect every user to have .NET framework on their system, so we can't go for this solution.

We can write a control through java applets which solves our problem. For this, we got to use the "URL"  and "URLConnection "object to open the connection to the URL and this "URLConnection" object provides a method by which we can get the response stream. Similarly we got to read from the response stream using "read" method.

Once the applet has been created we can include it in an HTML page through the "Applet" tag. From technology point of view, this is much simpler than writing an ActiveX control but a problem might arise if Microsoft doesn’t support it in the future or introduces a patch for it. This may lead to rewriting of the code.

Thus the best approach would be to use Microsoft technology, so we will concentrate only on ActiveX control as it is currently supported by .NET.

About ActiveX Control

The term 'ActiveX' refers to an extension of existing OLE and COM technologies and an ActiveX control is an object that supports a customizable, programmatic interface. Using the methods, events, and properties exposed by a control, Web authors can automate their HTML pages. Examples of such controls include text boxes, command buttons, audio players, video players, stock tickers, and so on.

Possible solutions

The following are the possible solutions which can be used to solve our problem but I will explain the problems of first two methods and why we are going for the third method.

1. INET control - This is an ActiveX control provided by Microsoft for internet transfer of files. It provides a method called getChunk where we can get chunks of data from the response stream and openUrl method where we can get the entire data from the response stream but this control has some problem while downloading files.

It most often then not, gives a "Runtime error 13 type mismatch" message. This is a known problem and the web is flooded with people asking for help regarding this. Another problem with this control is, it doesn’t provide the number of bytes being downloaded so we can't give an accurate display of progress being made.

2 Winsock control - This is an ActiveX control provided by Microsoft for network programming. It uses sockets, to connect to the server and get the files. It works fine but for performance and programmer friendliness. There are delays in connecting to the server and the opening and closing of sockets has to be done by the programmer in order to prevent resource leaks. It's basically a low level control where the programmer has to do the bulk of the work.

3. Wininet dll - This DLL contains a set of API's provided by Microsoft for internet transfer of files. Performance is better in this case since we are directly using the API's and not relying on another control to provide the functionality. It has no problems as far as downloading of files is concerned so we would be using this DLL to solve our problem.

Solution

Software Requirements

1. VB6 for client side code
2. .NET framework for server side code
3. Window 2000 or NT and above

Server Side Code

As I said before, we would need to write just 8 lines of code.

1. Create a new ASP.NET project with VB.NET as code behind and name it as MyDownload.

2. Add a new webform called download.aspx and paste this piece of code in the aspx file page_load procedure.

Private Sub Page_Load( ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        Response.ContentType = "application\octet-stream"
 Dim filename as string=new string("c:\\downloads\\hi.doc") 
        Dim downloadFile As System.IO.FileStream = New System.IO.FileStream(filename, IO.FileMode.Open)
        Response.Write(downloadFile.Length() & "#")
        downloadFile.Close()
        Response.WriteFile(filename)
        Response.Flush()
        Response.End()
End Sub

The logic behind this code is to first write the file length into response stream with "#" as delimiter between the file length and the data, followed by the file content into the response stream.

We are passing the file length in order to show an accurate display of progress made in the progress bar when downloading takes place. It's very important and a good programming practice to close the file stream and response stream after using it.

3. Build the project and it's all set as far as server side is concerned.

Client Side Code

1. Create a new ActiveX control VB project called FileDownload.

2. Before proceeding to write the code for downloading the file, we need to add the API declaration of wininet.dll to the project. So add a new module called wininet API and paste the following code in it.

Option Explicit

Public Const INTERNET_OPEN_TYPE_PRECONFIG = 0
Public Const INTERNET_OPEN_TYPE_DIRECT = 1
Public Const INTERNET_OPEN_TYPE_PROXY = 3
Public Const scUserAgent = "VB OpenUrl"
Public Const INTERNET_FLAG_RELOAD = &H80000000
Public Declare Function InternetOpen Lib "wininet.dll" Alias "InternetOpenA" _
(ByVal sAgent As String, ByVal lAccessType As Long, ByVal sProxyName As String, _
ByVal sProxyBypass As String, ByVal lFlags As Long) As Long
Public Declare Function InternetOpenUrl Lib "wininet.dll" Alias "InternetOpenUrlA" _
(ByVal hOpen As Long, ByVal sUrl As String, ByVal sHeaders As String, _
ByVal lLength As Long, ByVal lFlags As Long, ByVal lContext As Long) As Long
Public Declare Function InternetReadFile Lib "wininet.dll" _
(ByVal hFile As Long, ByVal sBuffer As String, ByVal lNumBytesToRead As Long, _
lNumberOfBytesRead As Long) As Integer
Public Declare Function InternetCloseHandle Lib "wininet.dll" _
(ByVal hInet As Long) As Integer


3. Change the name of the user control to FileDownloadCtrl.

4. Add a frame to the user control and place the following labels and the progress bar inside the frame.

 a) lblByteD- set its caption to "Bytes Downloaded".
 b) lblBytesDownloaded- set its caption to "".
 c) lblFileS- set its caption to "FileSize in Bytes".
 d) lblFileSize- set its caption to "".
 e) pgDownload - set progressbar name to "pgDownload"

5. Use the "activex control interface wizard" in vb6's add-in menu to create a new function called downloadFile with the following declaration:

Public Function downloadFile(url As String, filename As String, ByRef errno As Integer) As Boolean

Parameters

  • url - is the url of your download.aspx file e.g.http://localhost/Mydownload/download.aspx
  • filename - is the name with which the downloaded file has to be saved as in the client machine.
  • errno - gives the errorno if any error has occurred.

Returns

  • True or false depending on whether the operation was success or not

6 Once you have finished all the steps in the wizard. It would have generated lots of code. Find downloadFile function in the code and do the following

  • Write the error handling statement and add the following variables

On Error GoTo errhandle
Dim hOpen As Long
Dim hOpenUrl As Long
Dim sUrl As String
Dim bDoLoop As Boolean
Dim bRet As Boolean
Dim sReadBuffer As String * 2048
Dim lNumberOfBytesRead As Long
Dim sBuffer As String
Dim percent As Integer
Dim file As String
Dim flen As Long

  • Next step is to open a connection to the URL passed as the parameter. This is done with the help of two API's "InternetOpen" and "InternetOpenUrl" provided by wininet.dll

sUrl = url
hOpen = InternetOpen(scUserAgent, INTERNET_OPEN_TYPE_PRECONFIG, vbNullString, vbNullString, 0)
hOpenUrl = InternetOpenUrl(hOpen, sUrl, vbNullString, 0, INTERNET_FLAG_RELOAD, 0)

  • Once the connection is obtained, we got to read the file size from the response stream which would be done by reading byte by byte till we reach "#" character. To read from the response stream we use another API of wininet dll called "InternetReadFile".This function takes 4 parameters

ohOpenUrl -the return value of "InternetOpenUrl"
osReadBuffer - buffer into which the data has to be written from the response stream
o1 - no of bytes to read which is specified by us; in our case it is one
olNumberOfBytesRead - it is the actual bytes which was read

bDoLoop = True
    'get file size
While bDoLoop
      bRet = InternetReadFile(hOpenUrl, sReadBuffer, 1, lNumberOfBytesRead)
      If (Left$(sReadBuffer, 1) = "#") Then
            bDoLoop = False
      Else
            file = file & Left$(sReadBuffer, 1)
      End If
Wend

  • Next step is to set the value of progress bar initially to "0" then increase as the bytes are downloaded. We also set the filesize label to its value.
     
    flen = CLng(file)   
    lblFileSize.Caption = file
    lblFileSize.Refresh
    percent = 0
    pgDownload.Value = percent

  • We now come to main part, downloading of the file from the stream. We will use a simple while loop which repeatedly called "InternetReadFile" function, till number of bytes read is zero.

bDoLoop = True
Dim cnt As Long
cnt = 0
     While bDoLoop
         sReadBuffer = vbNullString
         bRet = InternetReadFile(hOpenUrl, sReadBuffer, Len(sReadBuffer), lNumberOfBytesRead)
      sBuffer = sBuffer & Left$(sReadBuffer, lNumberOfBytesRead)
            percent = Int((Len(sBuffer) / flen) * 100)
         cnt = cnt + lNumberOfBytesRead
         If (cnt > 10000) Then
       lblBytesDownloaded.Caption = CStr(Len(sBuffer))
       lblBytesDownloaded.Refresh
       cnt = 0
End If
      pgDownload.Value = percent
         if Not CBool(lNumberOfBytesRead) Then
        bDoLoop = False
             End If
Wend

Cnt variable is used to refresh the bytesdownloaded label for every 100kb read, since progress bar's value property expects the value to be between 1 and 100, we calculate the percentage of bytes read by dividing the total bytes read by the file size.

  • The last step is to save the file to hard disk. For this we use open function and write the content of "sBuffer" into the file

Open filename For Binary Access Write As #1
 Put #1, , sBuffer
Close #1

  • We set the value of progress bar to 100 only here, since there might be some delay in writing to the hard disk. We will also close the connections, in order to prevent any memory leak once the work is done.

   
pgDownload.Value = 100
lblBytesDownloaded.Caption = file
lblBytesDownloaded.Refresh   
If hOpenUrl <> 0 Then InternetCloseHandle (hOpenUrl)
If hOpen <> 0 Then InternetCloseHandle (hOpen)

  
7. With the above steps, we have finished developing the code for downloading the files and only the creation of the ActiveX control remains. To do it, click on File menu of VB IDE and select "make filedownload.ocx", click on it and voila!!, your ActiveX control is ready.

8. For the control to be installed on the client machine, we need to package it into CAB file. This can be done with the help of "Package and Deployment Wizard" provided by Visual Studio6.

9. The wizard would generate a CAB file and a HTM file. Copy the two files to your webserver's virtual directory and write a small javascript function in the HTM file which would call the control's downloadFile method. Eg

<script language=javascript>
function download()
{
 var b,errno,errdesc,errsrc;
FileDownloadCtrl.downloadFile("
http://localhost/Mydownload/download.aspx", "c:\\downloads\\hi.doc",errno);
}
</script>

10. The one thing that you have to keep in mind is you need to sign the ActiveX control, for it to be installed on the client machine without changing the security settings of Internet Explorer.

If you are planning to give an unsigned ActiveX control then on the client machine' Internet explorer, you have to select,

"internet options->security->internet"

and reduce it to the lowest level.


blog comments powered by Disqus
ASP.NET ARTICLES

- How Caching Means More Ca-ching, Part 2
- How Caching Means More Ca-ching, Part 1
- Reading a Delimited File Using ASP.Net and V...
- What is .Net and Where is ASP.NET?
- An Object Driven Interface with .Net
- Create Your Own Guestbook In ASP.NET
- HTTP File Download Without User Interaction ...
- Dynamically Using Methods in ASP.NET
- Changing the Page Size Interactively in a Da...
- XML Serialization in ASP.NET
- Using Objects in ASP.NET: Part 1/2
- IE Web Controls in VB.NET
- Class Frameworks in VB .NET
- Cryptographic Objects in C#: Part 1
- Sample Chapter: Pure ASP.Net

Watch our Tech Videos 
Dev Articles Forums 
 RSS  Articles
 RSS  Forums
 RSS  All Feeds
Write For Us 
Weekly Newsletter
 
Developer Updates  
Free Website Content 
Contact Us 
Site Map 
Privacy Policy 
Support 

Developer Shed Affiliates

 




© 2003-2017 by Developer Shed. All rights reserved. DS Cluster - Follow our Sitemap
Popular Web Development Topics
All Web Development Tutorials