Showing posts with label VB.NET. Show all posts
Showing posts with label VB.NET. Show all posts

Saturday, April 30, 2011

The 'My' Namespace in a VB.NET Application is Missing Members

OK I ran across this little snag in a VB.NET application, and thought I might share an easy solution to the problem. If you ever have a .NET solution that originated in a previous version other than 2010 and has been upgraded, you might have some difficulty accessing members of the 'My' namespace. Specifically I was missing the auto generated 'MyWebExtensions.vb' code file displayed below:


This resulted in the "'Application' is not a member of 'My'" error:


There are probably a few tricks you could make to the solution (.sln) file by opening it in Notepad and fixing the appropriate settings, but the easiest way to fix the error is to remove the 'My' extension and add it back into the project. To do this open the project's properties of the project where the error is occurring, and click on the "My Extensions" tab.


The 'My' extension you need for your project is dependent on the type of project you have created (Web, WPF, etc.), so make sure to select the proper one when re-adding. First though, right-click the current extension already added and select “Remove Extension”


Then press the "Add Extension" button in the bottom right-hand corner, and add the appropriate extension back into your project. This should auto-generate the 'MyWebExtensions.vb' code file and fix any previously non-accessible members in the 'My' namespace.


For more information on the 'My' namespace, check out the (2) MSDN links below:

My Namespace

How My Depends on Project Type (Visual Basic)

Monday, November 1, 2010

Download FTP Files Using FTP Over SSL (SFTP) in .NET

Recently with the help of some folks over at StackOverflow I got pointed in the right direction for working with files on a FTP server and communicating with it via FTP over SSL. I had success using FTP client software to view and download files, but needed the code to do this programmatically in .NET. It is essentially easier than I thought and just casts a 'WebRequest' object to an 'FTPWebRequest' object and then the methods called are identical to those used in a traditional WebRequest call.

The main 3 obstacles I ran into where the following:

- Getting the Object parameter values set properly to match those of the client software I was already having success connecting with.
- Validating the Server's SSL Certificate programmatically.
- Getting around a 550 error I kept receiving when accessing the file directly.

So let’s get right to all of the code:

'Using an anonymous method, check to make sure the SSL Certificate being served up is the correct one.
'This method of inlining the validation is good for a simple single certificate check; for more involved
'checking you will want to use the line below and long hand the method call.
ServicePointManager.ServerCertificateValidationCallback = Function(obj As [Object], certificate As X509Certificate, chain As X509Chain, errors As SslPolicyErrors) (certificate.Subject.Contains("CN=ftp.domain.com"))
'Wire up a method that will be called upon creating the FTtpWebRequest and will validate the SSL Certificate
'ServicePointManager.ServerCertificateValidationCallback = New System.Net.Security.RemoteCertificateValidationCallback(AddressOf CertificateValidation)

'Create an FTPWebRequest providing the URI of the FTP server to connect
Dim Request As System.Net.FtpWebRequest = DirectCast(WebRequest.Create(New Uri("ftp://sftp.domain.com/MyFiles/Folder1/MyFile.txt")), System.Net.FtpWebRequest)
'Set that we will be downloading a file
Request.Method = WebRequestMethods.Ftp.DownloadFile
'We are going to enable SSL for the communication with the FTP server as required by the remote server.
Request.EnableSsl = True
'The credentials needed to log onto the server
Request.Credentials = New Net.NetworkCredential("UserName", "Password")
'Use a 'Passive' data transfer process. This setting was the same in my FTP client software.
Request.UsePassive = True
'Create a 'Reponse object getting the downloaded file
Dim Response As System.Net.FtpWebResponse = DirectCast(Request.GetResponse(), System.Net.FtpWebResponse)

'Read the File using a StreamReader:
Dim sr As New StreamReader(Response.GetResponseStream())
To solve my 1st issue I mentioned (get object parameters set), I essentially found and configured the FTPWebRequest object to mimic an existing workable connection from my client software. A lot of the FTP 'lingo/jargon' is identical between .NET and FTP client software. I recommend connecting to the FTP server as I did 1st using client software (i.e. FileZilla) to make sure you do have everything correct before running in circles with code that would never work because you don’t have permissions anyway.

Next I had to validate the servers SSL certificate programmatically. I was able to use a Lambda Expression using an anonymous method to to create a delegate that would check to make sure the proper SSL Certificate was being presented. If the validation logic is more elaborate, you can use the commented out call to wire up an event to a method named 'CertificateValidation()' by assigning the ServerCertificateValidationCallback on the ServicePointManager object.

Private Shared Function CertificateValidation(ByVal sender As Object, ByVal cert As X509Certificate, ByVal chain As X509Chain, ByVal [error] As System.Net.Security.SslPolicyErrors) As Boolean

'Make sure the correct certificate is being used:
If cert.Subject.Contains("CN=ftp.domain.com") Then
Return True
Else
Return False
End If

End Function
Now either method could technically just return 'True' and all certificates would be trusted and validated, but I wanted to make sure I am actually presented with the correct certificate. You can easily find out the name of the certificate by turning on tracing in the web.config (explained below). Then you can make sure the proper certificate was served, and then Return True. This process actually exists the 1st time you probably connected to the FTP server with the FTP client software (i.e. FileZilla). A dialog probably presented itself asking if you trusted the certificate. This code is dealing with that process programmatically.

The last fix was in regards to solving this specific issue:

"The remote server returned an error: (550) File unavailable (e.g., file not found, no access)."

Now this was probably an issue specific to my setup, but I mention it because the oversight is probably common. I received this upon getting the FtpWebResponse object. The issue stemmed from the URI I was providing. I knew the URI had to be the full path to the file I wanted to download, so I used ftp://sftp.domain.com/MyFiles/Folder1/MyFile.txt I tried in a browser and had the same issue. I ended up turning on a listener to log System.Net traffic. The following article has directions on doing this: Using System.Net Tracing This output (found in the root folder in my project after running) showed that the default path was already /MyFiles/Folder1. This was already the path as soon as I connect to the base URI of sftp.domain.com, and I should have recognized this from the FTP client software, as I was directly taken to this folder location each time I connected. Therefore, when I fully qualified the URI, it actually resulted in looking for the following: ftp://sftp.domain.com/MyFiles/Folder1/MyFiles/Folder1/MyFile.txt This showed me that all I needed to do was just use the host + filename like the following which worked perfectly: ftp://sftp.domain.com/MyFile.txt

This code demonstrated how to download a file from a FTP server using SSL, but there are many other operations you can do as well (i.e. Uploading, file renaming, directory listing, etc.). Just modify the Enumeration value of 'Request.Method'.

Tuesday, June 1, 2010

Using Auto-Properties and Traditional Properties with VB.NET in VS.NET 2010

Once you being using VS.NET 2010 as a VB.NET user, you will soon see the neat feature of Auto-Properties which C# users have enjoyed since VS.NET 2008. I will not go too much into them as the feature has been covered exhaustively across blogs and sites. In a nutshell the Auto-Property feature provides a short hand way of defining properties without having to fully write out the Get and Set code, along with the backing variable.

But what if you do need a more advanced property, where the data is manipulated? How do I get back to the more explicit long-hand format of a property if I need it? At least in VS.NET 2008, after finishing the definition of the property and its type and pressing <enter> the template was generated for me, so how do I recreate this in VS.NET2010?

The answer is to type in 'prop' (without quotes) which will show an Intellisense menu of built in snippets including the needed 'Property' code (shown below):


Type in 'prop' and hit the tab key twice to produce the long-hand explicitly defined version of the Property. In fact even this is 1 up from VS.NET 2008 as it creates the backing variable right on top of the property. All you need to do is tab through the fields to modify the values as needed. The long-hand version of the property is displayed below:


Monday, April 5, 2010

How To: Use Recursion in .NET To Delete All Files and Directories in .NET

Have you ever needed to have some code delete all of the folders and files below a given directory? Maybe the reason is for an automated cleanup that runs on schedule, or just cleaning up cache files after a given period of time. Whatever the reason, a good way to do this in .NET is to write some methods and call them recursively to delete out all files in the lowest level directory, making its way back up to the top level. And of course deleting the directories (folders) themselves after all files within are deleted.

At this point you may be saying, "Can’t I just write some code to iterate through all of the directories, and delete the directories and files in a single operation?" Well you could try it by just calling the basic overload for .Delete(), but you would quickly come across the following exception being thrown:

"The directory is not empty."

This is because the default overload of the .Delete() method of the directory object, will not let you delete it if there are any files still within that directory. Regardless, you may actually need to observe each file prior to deletion to examine its creation date, file attributes, etc. prior to deletion and this is not possible when the single delete is done on the entire directory and all of its files. Therefore we must traverse downward through all directories, deleting out all of the files within before deleting the containing directory. This can all be done using recursion and some operations from the System.IO namespace in .NET.


You may have also gone down this path, but hit another bump when you received the following exception upon deleting a file:

"Access to the path 'MyFile.doc' is denied."

This occurs because read-only files can also not be deleted; we will take care of this by changing the file attributes to not be 'Read-Only' prior to deletion. This however brings up an important last point: many times file deletion regardless of file attributes requires an elevated permission. Therefore you may need to wrap the following code using impersonation of an elevated account, or just make sure that the directories and files being deleted have the proper permissions allowed at the root level. Either solution will work fine.


I want to emphasize this entry more around how to use recursion in operations such as deleting files, but not focus too heavily on the file delete example. Recursion is a powerful and often overlooked method of writing good streamlined clean code. I find those that were formally educated in Software Engineering or Computer Science are well familiar with concepts like recursion, where as the Barnes and Noble book learned developer may have not used some of these methods before. That's perfectly fine, and hopefully this will help you understand recursion better and be able to use it in the future. In fact, if you are 100% only interested in deleting all files in a directory without needing the ability to observe each file prior to deletion then you can provide a boolean value to the 2nd parameter in the overload of the 'Delete()' method that will delete all files in a directory before deleting the directory for you all in 1 line of code shown below:

System.IO.Directory.Delete("C:\TempTest", True)
So without further ado, let's get to the code. It has quite a bit of commenting injected to help explain the process. You may want to test it out on a directory that has multiple levels and files, before using it on anything live to make sure you have your version working properly.


Public Sub TestDelete()

'Get an object repesenting the directory path below
Dim di As New DirectoryInfo("C:\MyTestDirectory")

'Traverse all of the child directors in the root; get to the lowest child
'and delte all files, working our way back up to the top. All files
'must be deleted in the directory, before the directory itself can be deleted.
For Each diChild As DirectoryInfo In di.GetDirectories()
TraverseDirectory(diChild)
Next

'Finally, clean all of the files directly in the root directory
CleanAllFilesInDirectory(di)

End Sub

'''
''' A method to traverse down through child directories until
''' we have reached the lowest level and then clean (delete) all
''' files before deleting the directory itself.
'''

'''
''' All files must be deleted in a directory prior to deleting the
''' directory itself to prevent the following exception:
''' "The directory is not empty."
'''

Private Sub TraverseDirectory(ByVal di As DirectoryInfo)

'If the current directory has more child directories, then continure
'to traverse down until we are at the lowest level. At that point all of the
'files will be deleted.
For Each diChild As DirectoryInfo In di.GetDirectories()
TraverseDirectory(diChild)
Next

'Now that we have no more child directories to traverse, delete all of the files
'in the current directory, and then delete the directory itself.
CleanAllFilesInDirectory(di)


'The containing directory can only be deleted if the directory
'is now completely empty and all files previously within
'were deleted.
If di.GetFiles().Count = 0 Then
di.Delete()
End If

End Sub

'''
''' Iterates through all files in the directory passed into
''' method and deletes them.
'''

'''
''' It may be necessary to wrap this call in impersonation or ensure parent directory
''' permissions prior, because delete permissions are not guaranteed.
'''

Private Sub CleanAllFilesInDirectory(ByVal DirectoryToClean As DirectoryInfo)

For Each fi As FileInfo In DirectoryToClean.GetFiles()
'The following code is NOT required, but shows how some logic can be wrapped
'around the deletion of files. For example, only delete files with
'a creation date older than 1 hour from the current time. If you
'always want to delete all of the files regardless, just remove
'the next 'If' statement.
If fi.CreationTime < Now.Subtract(New TimeSpan(0, 0, 1)) Then
'Read only files can not be deleted, so mark the attribute as 'IsReadOnly = False'
fi.IsReadOnly = False
fi.Delete()

'On a rare occasion, files being deleted might be slower than program execution, and upon returning
'from this call, attempting to delete the directory will throw an exception stating it is not yet
'empty, even though a fraction of a second later it actually is. Therefore the 'Optional' code below
'can stall the process just long enough to ensure the file is deleted before proceeding. The value
'can be adjusted as needed from testing and running the process repeatedly.
System.Threading.Thread.Sleep(50) '50 millisecond stall (0.05 Seconds)
End If
Next
End Sub


This code should be almost 'copy and paste' ready to run in your application. The main modification needed is to change the root directory referenced in the initial DirectoryInfo object. Also notice the optional code I added to show how you can wrap the file deletion in conditional code stating to only delete files older than 1 hour. This is not required, but shows you how the code can easily be modified.

Tuesday, November 10, 2009

How To: Sort Items in an ASP.NET ListBox Control

The need may arise in an ASP.NET application to have several items added to a ListBox by the user at runtime. However, the added items may not show up in order (alphabetically, etc.) by default. The following easy to implement method will take in a ListBox control and sort the items in it. This is a perfect method to create as 'Shared' (VB.NET) or 'Static' (C#) in a Utilities class that is easily accessible.

The work is done by copying the ListBoxItems out of the ListBox and into a List(of ListItem) object collection. This secondary collection can then be manipulated via a 'Comparison' delegate with the address of a method that will compare the (2) items and return them in order. The ordered List of objects is then added back to the original control after being cleared, and the result is having the items in order.

All that the caller needs to do is pass the ListBox control in as a parameter. This could possibly be called on PostBack when the item is added, or maybe upon some other user interaction that calls this method. Another idea might be to use an AJAX UpdatePanel around the ListBox to asynchronously postback to sort the items without a full postback.

Here are the (2) methods needed to sort the ListBox control:


Public Shared Sub SortListBox(ByVal lbxId As ListBox)

Dim t As New List(Of ListItem)()
Dim compare As New Comparison(Of ListItem)(AddressOf CompareListItems)

'Iterate through each ListItem in the Listbox, and add them to the 'List' object
For Each lbItem As ListItem In lbxId.Items
t.Add(lbItem)
Next

'Sort the List
t.Sort(compare)

'Clear the Listbox passed in, and add the sorted list from above
lbxId.Items.Clear()
lbxId.Items.AddRange(t.ToArray())

End Sub

Public Shared Function CompareListItems(ByVal li1 As ListItem, ByVal li2 As ListItem) As Integer

'Return the strings in order that have been compared:
Return [String].Compare(li1.Text, li2.Text)

End Function


And here is an example of calling the method above to sort the ListBoxItems:


'Sort the ListBox control items on the .aspx page
SortListBox(Me.lbxMyItems)

That's all you need to sort the ListBox control. You could also easily change the 'CompareListItems' method to compare the items other than by 'String' which will ultimately make the items appear in alphabetical order. If you did this you may want to overload or extend the original method so that it could be called to sort the items in various ways.

Monday, November 2, 2009

Tools for Converting C# code to VB.NET (or vice versa) and a little => ... Function(), Lambdas too

This seems to be common knowledge for the majority of .NET developers that need help converting C# code to VB.NET or the other way around, but from time to time I still see a new developer to the community that does not know of the avaliable tools to help with this. I also have seen that even some of the more seasoned developers are unaware that there is more than (1) site avaliable to help with this conversion process. So without further ado, here are (3) sites with brief descriptions that will help users conver C# to VB.NET code:

  1. developerFusion's Convert C# to VB.NET - This is probably the most well know site and referenced most often. I typically start with this one: http://www.developerfusion.com/tools/convert/csharp-to-vb/
  2. Code Converter Provided by Telerik - This is another great and stable converter online. I typically go to this one if the code to convert is complex or there were any issues with the converter: http://converter.telerik.com/
  3. KamalPatel.Net - Convert C# to VB .NET - Several years ago I used this one as the defacto converter, but somewhere along the lines the code I was converting was getting too complex, or the site was not upkept anymore because it shows issues converting often. I now come here lastly: http://www.kamalpatel.net/ConvertCSharp2VB.aspx

Now, one of the issues all the converters seem to have issue with is .NET Lambda Expressions. Recently, I have found several powerful code snippets in C# including Labmda expressions that none of the converters would convert properly. This code will need a little extra help in getting it converted. Below I have a brief example of a C# Labmda expression and the equivelent VB.NET code that I had to modify. Hopefully, this code will help guide readers to get started with a proper conversion of Lambda expressions.


The C# version:


.Aggregate(new StringBuilder(), (sb, node) => sb.Append(node.ToString()), sb => sb.ToString());

The VB.NET version:


.Aggregate(New StringBuilder(), Function(sb, node) sb.Append(node.ToString()), Function(sb) sb.ToString())

Both code examples take use of passing values to a function to shorthand the return, however in VB.NET the syntax is more explicit with the 'Function' statement being required. A good reference for Lambda expressions for each language can be found below.


Lambda Expressions (VB.NET):
http://msdn.microsoft.com/en-us/library/bb531253.aspx

Lambda Expressions (C#):
http://msdn.microsoft.com/en-us/library/bb397687.aspx

This was by no means a full entry on .NET Lambda expressions, but I just wanted to briefly highlight some of the differences syntactically between the (2) languages, and where the converters may have issue with more complex code.

Tuesday, October 20, 2009

How To: Strip Illegal XML Characters from a String in VB.NET

Recently I was having some trouble with string data that was being sent to an .asmx web service I had built and returning the following exception message:

"Response is not well-formed XML System.Xml.XmlException: ' ', hexadecimal value 0x13, is an invalid character."

The origination of this cause was due to my users copying and pasting data from Microsoft Word into a WYSIWYG editor that was preserving illegal characters, such as the one ('!!') shown in the exception above.

Rather than put in place some calls shielding the web service from the bad data, I decided to research building a method that would strip out and remove illegal characters prior to placing the data into my business object on the front end. Of coarse I could check it on the back end too to be thorough, but this is what was appropriate for my scenario.

There turns out to be some information on this topic, but oddly enough most of the solutions were written for Java and PHP. The .NET solutions I found were only half working and not complete. The best solution I came across was one written in Java at
Ben J. Christensen's Blog. With the help from users on the ASP.NET forums here I was able to place all the information I had found together to come up with a VB.NET version of the code. I really credit Ben and the forum for the base code help; thank you.

The code's purpose is to take the passed in string value, and check each character 1 by 1 to see if any illegal XML characters exist. All valid characters are re-appended to the output, and illegal characters are omitted.

If you need the C# version check the forum link I provided above. The main difference is that the 'AscW' function that wraps the character in focus is not required in C#. This is because C# and VB.NET deal differently in character to integer conversions. The final code is below, and hopefully this .NET version will help somebody in the future as it did for me.


Public Shared Function RemoveIllegalXMLCharacters(ByVal Content As String) As String

'Used to hold the output.
Dim textOut As New StringBuilder()
'Used to reference the current character.
Dim current As Char
'Exit out and ruturn an empty string if nothing was passed in to method
If Content Is Nothing OrElse Content = String.Empty Then
Return String.Empty
End If

'Loop through the lenght of the content (1) character at a time to see if there
'are any illegal characters to be removed:
For i As Integer = 0 To Content.Length - 1
'Reference the current character
current = Content(i)
'Only append back to the StringBuilder valid non-illegal characters
If (AscW(current) = &H9 OrElse AscW(current) = &HA OrElse AscW(current) = &HD) _
OrElse ((AscW(current) >= &H20) AndAlso (AscW(current) <= &HD7FF)) _
OrElse ((AscW(current) >= &HE000) AndAlso (AscW(current) <= &HFFFD)) _
OrElse ((AscW(current) >= &H10000) AndAlso (AscW(current) <= &H10FFFF)) Then
textOut.Append(current)
End If
Next

'Return the screened content with only valid characters
Return textOut.ToString()

End Function

Someone had asked how this method could be modified to accept and return an 'XmlDocument' type. The method only needs a few small code changes to support this, and would make a good overload to the original funtion. You will need to import the System.XML and System.IO namespaces for this overload.


Public Shared Function RemoveIllegalXMLCharacters(ByVal XmlDoc As XmlDocument) As XmlDocument

'Use a StringWriter & XmlTextWriter, to extract the raw text from the XmlDocument passed in:
Dim sw As New StringWriter()
Dim xw As New XmlTextWriter(sw)
XmlDoc.WriteTo(xw)
Dim Content As String = sw.ToString()

'Used to hold the output.
Dim textOut As New StringBuilder()
'Used to reference the current character.
Dim current As Char
'Exit out and ruturn an empty string if nothing was passed in to method
If Content Is Nothing OrElse Content = String.Empty Then
Return Nothing
End If

'Loop through the lenght of the content (1) character at a time to see if there
'are any illegal characters to be removed:
For i As Integer = 0 To Content.Length - 1
'Reference the current character
current = Content(i)
'Only append back to the StringBuilder valid non-illegal characters
If (AscW(current) = &H9 OrElse AscW(current) = &HA OrElse AscW(current) = &HD) _
OrElse ((AscW(current) >= &H20) AndAlso (AscW(current) <= &HD7FF)) _
OrElse ((AscW(current) >= &HE000) AndAlso (AscW(current) <= &HFFFD)) _
OrElse ((AscW(current) >= &H10000) AndAlso (AscW(current) <= &H10FFFF)) Then
textOut.Append(current)
End If
Next

'Build a new XMLDocument to return containing the screened content with only valid characters
Dim XmlDocClean As New XmlDocument
XmlDocClean.LoadXml(textOut.ToString())
Return XmlDocClean

End Function