FtpWebRequest.GetRequestStream hang up and fails. - vb.net

I have wrote a web service, in a nutshell it uses openpop to get email messages does stuff with the content to insert into databases and saves attachments which are images. That works fine when i save images locally, it does exactley what it is suppose to. Now an added requirment was to save images to an FTP directory, so i can create my folders dynamically (they are created based upon timestamp) and that works well. My problem comes from when i try to save them to the ftp. Yes my user name and password are correct, otherwise i wouldn't be creating the directory.
Private Sub UploadFile(ByVal fileToSave As FileInfo, ByVal path As String)
Dim UploadRequest As FtpWebRequest = DirectCast(WebRequest.Create("ftp://UserName:Passowrd#999.99.999.9" & path), FtpWebRequest)
UploadRequest.Credentials = New NetworkCredential("PicService", "grean.matching18")
UploadRequest.Method = System.Net.WebRequestMethods.Ftp.UploadFile
UploadRequest.UseBinary = True
UploadRequest.UsePassive = True
' Const BufferSize As Integer = 2048
' Dim content(BufferSize - 1) As Byte, dataRead As Integer
Dim bFile() As Byte = System.IO.File.ReadAllBytes(fileToSave.ToString)
'UploadRequest.ContentLength = content.Length
Using FileStream1 As FileStream = fileToSave.OpenRead()
Try
'open request to send
Using RequestStream As Stream = UploadRequest.GetRequestStream
End Using
Catch ex As Exception
Finally
'ensure file closed
FileStream1.Close()
End Try
End Using
End Sub
I have tried using Passive False and Binary False as well, i did more research on my stack trace.
And found this article but no solution as of yet. Any input would be appreciated, i am also posting another question on windows services for different issue. If you would like to take a shot at it, the other question isnt about ftp but permissions for a service on windows server 2003

This may not be the solution but I've found that the URI string has to be 'just right' and that what is 'just right' varies by the ftp server.
So ftp://server/directory/file works on some servers but needs to be ftp://server//directory/file to work on others (note the double slash after the server name)
Aso, your URI has 'password' spelled incorrectly: ftp://UserName:Passowrd#999.99.999.9 and you are supplying the credentials in a separate code line as well.

Related

File Being Used By .NET Mail

I wrote a simple program written to collect files, send the files, then delete said files. I am sending them via Email using System.Net.Mail
If Label6.Text = "" Then
mail.Attachments.Add(New Attachment(zipPath))
End If
'Enables SSL, if required
ssl = Provider.ssl
If skipAhead = True Then
ssl = True
End If
If ssl = True Then
SmtpServer.EnableSsl = True
End If
'Sends the email
SmtpServer.Send(mail)
'Allows the user to either keep testing, or quit.
If skipAhead = True Then
My.Computer.FileSystem.DeleteFile(unalteredPath)
My.Computer.FileSystem.DeleteFile(unalteredPath1)
My.Computer.FileSystem.DeleteFile(zipPath)
Else
Dim keepOpen As Integer = MsgBox("The Email was sent. You can keep testing if you would like to. Press ok to close, and cancel to keep testing", MsgBoxStyle.OkCancel)
If keepOpen = 1 Then
Close()
End If
End If
As seen in line 2, the attachment is added to the email, and I do not attempt to delete the attachment until after the email is sent, however when the code is running, it throws an error that the file is being used by another process.
I am also wondering if this could be lingering from the .zip being created itself. Here is the code that does that:
Public Sub Zipping()
'Copies files to the folder where they will be zipped from
My.Computer.FileSystem.CopyFile(unalteredPath, outputs & "\ExIpOutput.txt")
My.Computer.FileSystem.CopyFile(unalteredPath1, outputs & "\IpConfig.txt")
'Deletes the old output files
My.Computer.FileSystem.DeleteFile(unalteredPath)
My.Computer.FileSystem.DeleteFile(unalteredPath1)
'Starts the zip Sub
ZipFile.CreateFromDirectory(outputs, zipPath, CompressionLevel.Fastest, True)
My.Computer.FileSystem.DeleteDirectory(outputs, FileIO.DeleteDirectoryOption.DeleteAllContents)
End Sub
Here is the CreateFromDirectory sub:
Public Shared Sub CreateFromDirectory(sourceDirectoryName As String, destinationArchiveFileName As String, compressionLevel As Compression.CompressionLevel, includeBaseDirectory As Boolean)
End Sub
Is there something I'm missing here, or do I need to have the program sleep for a bit to let the email send, then delete the .zip file?
You can load the file into an array: File.ReadAllBytes(String) Method.
Then get a MemoryStream from that: How do I convert struct System.Byte byte[] to a System.IO.Stream object in C#?
And finally, you can use a MemoryStream for an attachment: Attach a file from MemoryStream to a MailMessage in C#.
As the data to be sent is in memory, you should be able to delete the file. Note that if there is a crash, the data is gone.
The examples are in C#, but if you have problems using the methods in VB.NET, please edit your question to show how far you've got and tell us what the problem is.
A better solution to this issue is to dispose the Attachment object that is locking the file. Any object you create that has a Dispose method should have that method called when you're done with the object and an Attachment is no different.
Dim fileAttachment As Attachment
If Label6.Text = "" Then
fileAttachment = New Attachment(zipPath)
mail.Attachments.Add(fileAttachment)
End If
'...
SmtpServer.Send(mail)
If fileAttachment IsNot Nothing Then
fileAttachment.Dispose()
End If

VB.Net FTP read of dynamically generated file where FTPGetFileSize is not supported

I've been struggling with trying to read the configuration files on a device via FTP. The files are generated dynamically when the FTP request is sent, and the device does not support the FTPGetFileSize command.
I've lost count of the number of examples from the Web that I've tried in an attempt to solve this. Part of the problem is likely due to my inexperience with file streams. So, I'm looking for a kind soul that might be able to provide some insight.
In the code below, I'm trying two different methods. The first is a straight read of the entire file, the second attempts to control the read based whether there is anything coming in over the stream.
Both methods work on other devices that support the FTPGetFileSize command. But neither method works for this device.
Project form
Imports are:
Imports System.Net
Imports System.IO
Imports System.Text
The cmdGet_Click event code looks like this:
Dim sLocal_Path As String = "C:\Temp\FTP_Test\" + txtIPAddress.Text + "\"
System.IO.Directory.CreateDirectory(sLocal_Path)
' Complete the local path
sLocal_Path += txtFileName.Text
If System.IO.File.Exists(sLocal_Path) Then
System.IO.File.Delete(sLocal_Path) ' Make sure we don't have a collision.
End If
' Set up the Remote Path.
Dim sRemote_Path As String = "ftp://" + txtIPAddress.Text + "/gen:" + txtFileName.Text
Dim request As FtpWebRequest = CType(WebRequest.Create(sRemote_Path), FtpWebRequest)
request.Method = WebRequestMethods.Ftp.DownloadFile
request.Credentials = New NetworkCredential(FTP_User, FTP_Password)
request.UsePassive = True
request.Timeout = 15000
request.UseBinary = False
Dim response As FtpWebResponse = CType(request.GetResponse(), FtpWebResponse)
Dim responseStream As Stream = response.GetResponseStream()
Dim reader As StreamReader = New StreamReader(responseStream)
Dim writeFile As StreamWriter = New StreamWriter(sLocal_Path)
If RadioReadToEnd.Checked Then
' Write the FTP stream to the target file
writeFile.Write(reader.ReadToEnd()) ' works with static files.
Else
' Write the FTP stream as long as we have data coming in.
Dim ByteCount As Integer = 0
Threading.Thread.Sleep(500)
While Not (reader.Peek() = -1)
ByteCount += 1
If ByteCount > 4095 Then ' Go up for air after every block.
ByteCount = 0 ' Reset the byte counter for the next block.
Application.DoEvents()
End If
writeFile.Write(Chr(reader.Read))
End While
End If
reader.Close()
reader.Dispose()
writeFile.Close()
writeFile.Dispose()
responseStream.Close()
responseStream.Dispose()
Note that I put a delay in just before the While Loop in the hopes that maybe something would show up in the stream to keep the loop from terminating. Apparently I need some way to prime the pump.
Edit: The DOS FTP Get works fine. My assumption is that it has some way to get around the FTPGetFileSize not being supported. Is there a way to get the WebClient FTP Methods to do the same thing with a dynamically generated file?
I need a nudge (okay, a kick) in the right direction. Any suggestions are greatly appreciated!
It is now working! The problem turned out to be a missing '/' at the root of the path.
This particular device has a drive reference in it's path that other devices my routine talks to did not have. So, between that and the error being thrown regarding the file size, I was put off of the scent.
Thanks to Martin Prikryl's comment about showing a log, I went off to create a Wireshark recording, and that's when I noticed the missing slash when I compared it to the DOS FTP Get recording. So, while I'm a little red-faced, I hope my experience helps someone else who runs into a similar problem. But mostly, I'm very relieved that I did not have to go the route of writing an FTP Client that dealt with raw commands such as POST and RETR! The WebClient tools are now working very well for this application.

Streaming a pdf file to the browser from a LotusScript web agent

I'm creating a LotusScript web agent that reads the content of a pdf file somewhere on the network and returns it as a stream to the browser.
the agent will be called like this : getPDF?openAgent&pdfId=123456 and it should directly returns the pdf stream. (I didn't implement yet the url parameter catching)
Here's my current try, I still have an issue to convert the read buffer to the final stream
Sub Initialize
On Error GoTo errrorhandle
Dim session As New NotesSession
Dim stream As NotesStream
Set stream = session.CreateStream
Dim buffer As variant
Dim fileNum As Integer
Dim txt As String
Dim filename As String
Dim filecontent As String
filename = "C:\temp\test.PDF"
If Not stream.Open(filename,"binary") Then
MessageBox filename,, "Open failed"
Exit Sub
End If
If stream.Bytes = 0 Then
MessageBox filename,, "File has no content"
Exit Sub
End If
Print "content-type:application/pdf"
Do
buffer = stream.read(1)
Print buffer(0)
Loop Until stream.IsEOS
Call stream.Close
Exit Sub
errrorhandle :
Print "Error :" & Error & " at line : " & Erl
Exit sub
End Sub
It is not possible to output the pdf from a stream in Lotusscript.
I suggest you attach the pdf to a notesdocument and redirect the user to attached file url and later on remove the document.
you can get a hold of the saved pdf using the following syntax
http://server/database/unid/$File/myfile.pdf
Following on Thomas Adrian response, attaching the pdf into a document in a database and then serve the link as described is the best solution.
Keep in mind that this will require the user to be authenticated, if said database has or needs restricted access.
If the web users are not authenticated users, you'll need to give at least reader access to "Anonymous" in the ACL of the hosting database for this to work... which is not always advisable if the database has other purposes.
You can however create a dedicated database just for this purpose, with unrestricted ACL access.

Web application working on iis7 but not on local machine

I have my VB.NET web application successfully built and compiled on ISS7 server but on the local machine when compiling through Visual studion 2013 it is
returning "System.Security.Cryptography.CryptographicException: The system cannot find the file specified." error.
Not sure what is happening but throws an error at Dim cert As New X509Certificate2(certFile, certFilePassword,X509KeyStorageFlags.MachineKeySet)
Below is the code where I am trying to use a certificate that is installed on my local machine.
Sub LoginED(ByVal token As String)
Try
'We need the ED user ID
lblEDUserID.Text = GetEDUserID().ToString()
'Track user login
InsertLogin(txtEDUsername.Text, True)
'Set login cookies for ED users
If lblEDUserID.Text = "0" Then
lblEDLoginStatus.Text = "You have entered an incorrect login. Please try again."
Else
Dim certFile As String = "VIP_Cert.pfx"
Dim certFilePassword As String = "password"
Dim cert As New X509Certificate2(certFile, certFilePassword,X509KeyStorageFlags.MachineKeySet)
Dim vipSoapInterfaceQueryServiceCert As New WebReference.QueryService
'Dim fs As FileStream = File.Open(certFile, FileMode.Open, FileAccess.ReadWrite)
'Dim filesize As Long = fs.Length
'Dim buffer(filesize) As Byte
'fs.Read(buffer, 0, filesize)
'byte[] buffer = new byte[fs.Length];
'int count = fs.Read(buffer, 0, buffer.Length);
'fs.Close()
lblEDLoginStatus.Text = "Activation "
vipSoapInterfaceQueryServiceCert.ClientCertificates.Add(cert)
Dim vipSoapInterfaceService As New WebReference.GetCredentialInfoRequestType()
vipSoapInterfaceService.credentialId = "SMR23324543"
vipSoapInterfaceService.credentialType = WebReference.CredentialTypeEnum.STANDARD_OTP
vipSoapInterfaceService.requestId = "ABCD"
Dim vipSoapInterfaceResponse As New WebReference.GetCredentialInfoResponseType()
vipSoapInterfaceResponse = vipSoapInterfaceQueryServiceCert.getCredentialInfo(vipSoapInterfaceService)
lblEDLoginStatus.Text = "WebService Response: " + vipSoapInterfaceResponse.credentialId + ", Status:" + vipSoapInterfaceResponse.credentialStatus
End If
Finally
What I have tried so far:
1) Tried to specify the complete path of where the certificate file is on the machine.
2) Tried different formats of certificates (.pfx; .p12; .cer)
3) Tried the certificate open, read and sent into a buffer to take the input from a buffer.
(I removed the buffer logic when deploying on IIS7 as I placed the .pfx certificate file in System32 folder and the code could automatically recognise the certificate. But the local would not recognize)
4) I tried removing the "X509KeyStorageFlags.MachineKeySet" parameter. (I use that for the IIS7 compilation)
Any help is appreciated!!
Thanks! I could figure out what needed.
I had to create an App Pool for the Certificate and then provide Full Control permissions to that pool

How do I check if an ftp server is online and get the error that it generates if it is not connected?

I am new to programming in vb.net. I have come a long ways in my development and understanding of vb, but there is one hurtle I can not seem to fix. I am hosting an ftp server on my pc and I am making an app for it to connect to my server and download files. The problem with all the sample code is that everyone ASSUMES the server WILL be ONLINE. My pc may not be running 24/7 and I also may not have the ftp service running.In the first case it shouldnt even register that it is connected. In the second case, it WILL say that is connected b/c the pc is on, but it will return that the machine ou are trying to connect to is actively refusing the connection. Is there a way to TRULY check if the program is indeed connected to the server WITHOUT generating a bunch of Exceptions in the debugger? All I want is a call like:
Dim ftponline As Boolean = False 'Set default to false
ftponline = checkftp()
If ftponline Then
'continue program
Else
'try a different server
End If
So it would be a function called checkftp that returns a boolean value of true or false.
Here is my info:
Using Visual Studio 2010 Pro
Using .Net framework 4
Can anyone help?
Thanks!
I have tried the rebex ftp pack as well as the Ultimate FTP Pack.
Here is the updated code:
Public Function CheckConnection(address As String) As Boolean
Dim logonServer As New System.Net.Sockets.TcpClient()
Try
logonServer.Connect(address, 21)
Catch generatedExceptionName As Exception
MessageBox.Show("Failed to connect to: " & address)
End Try
If logonServer.Connected Then
MessageBox.Show("Connected to: " & address)
Return True
logonServer.Close()
Else
Return False
End If
End Function
Public Sub ConnectFtp()
types.Clear()
models.Clear()
ListBox1.Items.Clear()
ListBox2.Items.Clear()
TextBox2.Clear()
Dim request As New Rebex.Net.Ftp
If CheckConnection(*) Then
Dim tempString As String()
request.Connect(*)
request.Login(*, *)
request.ChangeDirectory("/atc3/HD_Models")
Dim list As Array
list = request.GetNameList()
Dim item As String = ""
For Each item In list
tempString = item.Split(New Char() {" "c})
If types.Contains(tempString(0)) = False Then
types.Add(tempString(0))
End If
If models.Contains(item) = False Then
models.Add(item)
End If
Next
request.Disconnect()
request.Dispose()
ElseIf CheckConnection(*) Then
request.Connect(*)
request.Login(*, *)
request.ChangeDirectory(*)
Dim list2 As Array
list2 = request.GetNameList()
Dim item2 As String = ""
Dim tempString2 As String()
For Each item2 In list2
MessageBox.Show(item2)
tempString2 = item2.Split(New Char() {" "c})
If types.Contains(tempString2(0)) = False Then
types.Add(tempString2(0))
End If
If models.Contains(item2) = False Then
models.Add(item2)
End If
Next
request.Disconnect()
request.Dispose()
End If
End Sub
No matter what I do, the second server will not connect. I even put a messagebox to show what items were being returned in the second server, but there are no messageboxes apearing when I run the program with my server offline. Is there anyone who can help?
If your code is designed with proper exception catching, it shouldn't be generating a "bunch" of exceptions. The first exception you catch should be your indication that the connection failed and your code should cease attempting to communicate at that point. If for some reason you really need to check the connectivity before attempting the FTP connection, you should be able to simply attempt to synchronously open a TCP socket to the FTP server's port. If that works, it's up and running.
You could simply open a socket to the server's IP address on Port 21 (assuming default FTP port).
I'm not much of a VB.Net programmer, but here's a link to sample code:
http://vb.net-informations.com/communications/vb.net_Client_Socket.htm
If you can establish the socket connection, you know that something is listening on that port (though you have not yet proven it's an FTP server, or that it will accept your login credentials...).
If you wish to simply avoid exceptions in the debugger, you could place the connection code in a method and apply the DebuggerHidden attribute to that method.