Tuesday, January 26, 2010

Add Missing Build Configuration DropDown to VS.NET

If you are like me, then you probably enjoy the convenience of the Build Configuration menu inside of Visual Studio.NET. This is the menu that contains the "Debug" and "Release" modes for project deployment configuration. Well when I build a new machine or re-install VS.NET, I notice that the build dropdown is not always displayed by default. So here are a few simple steps to get the menu back being displayed.

1. Goto the View -> Toolbars-> Customize menu in VS.NET. Select the 'Build' category on the left side, and scroll down to "Solution Configuration". Click and drag it to the location on your VS.NET menu where you would like it to be located. At this point you probably notice the dropdown is added, but is greyed out, and might not even have any option shown similar to the picture below (Step # 2 fixes this):


2. To now enable the menu goto the Tools -> Options menu. On the left side expand the "Projects and Solutions" section and select "General". Then on the right hand side, check the box that states "Show advanced build configurations".


That's it! You should now have an enabled build configuration menu in VS.NET.

Sunday, January 10, 2010

How To: Create an ASP.NET style Windows Authentication Policy for WCF Services

For those of you that program on a Windows Domain probably in a corporate environment, you were probably well familiar with using Windows Authentication in .asmx web services to restrict or permit users access. Do you remember how easy it was in a .asmx web service to allow only a specific user or group? Take a look below from the only setting needed in the web.config file associated with the web service:









That was it! Now let's not start off on the wrong foot here or give the wrong impression. I am a huge advocate of WCF over .asmx services and definently think it is the way to go. With WCF having such a broad use capability and granular level of control and functionality, came the loss of some of the bundled up functionality that was specific to IIS hosted .asmx web services. This is not a bad thing at all.

However, those of us that work with WCF came to quickly realize that with just a small configuration you could easily configure WCF to only allow Windows Authenticated users to access the service, but that was it. There was no clean direct way to restrict the Windows Users or Groups in a 'blanket' fashion as was the case with .asmx web services and the configuration shown above. Not even setting the WCF service to ASPCompatibilityMode could directly accomplish the configuration above.

So there are (2) main ways to get around this issue. The 1st method to get around this would be to define PrincipalPermission attributes on every method to define its security requirements. This means hardcoding the security requirements, and is not as flexible as info that comes from a .config file. In some cases this method by method style of security may be desired, but often our services are an all or nothing style of access.

The 2nd solution, and the focus of this article, is to intercept the authorization calls to your WCF service and examine the identity of the user making the call to determine if they are authorized. We as developers are provided the ability to extend the 'ServiceAuthorizationManager' class and override the 'CheckAccessCore()' method to define our own custom authorization policy for the service. It is within this method that you can scrutinize the individual roles, groups, or users authorized by extracting the WindowsIdentity of the context, and then either permitting or rejecting access based on your requirements. Within here you could pull the authorized roles, users, or groups from the WCF .config file.

To get right to the code, below I have provided the implementation of the overriden 'CheckAccessCore()' method. The robust comments within should detail well what each step is doing:


Imports System.Configuration
Imports System.Security.Principal
Imports System.IdentityModel.Tokens

'''
''' The Identity Model infrastructure in Windows Communication Foundation (WCF) supports an extensible claims-based authorization
''' model. Claims are extracted from tokens and optionally processed by custom authorization policies and then placed into an
''' AuthorizationContext. An authorization manager examines the claims in the AuthorizationContext to make authorization decisions.
''' By default, authorization decisions are made by the ServiceAuthorizationManager class; however these decisions can be
''' overridden by creating a custom authorization manager. To create a custom authorization manager, create a class that derives
''' from ServiceAuthorizationManager (this class) and implement CheckAccessCore method (done in this class). Authorization
''' decisions are made in the CheckAccessCore method, which returns 'true' when access is granted and 'false' when access is denied.
''' In our case, we are examining the Windows Identity of the current user's context and checking it against some predefined
''' permitted users and roles from the AppSettings section of the associated services' .config file.
'''

''' Because of performance issues, if possible you should design your application
''' so that the authorization decision does NOT require access to the message body.
''' Registration of the custom authorization manager for a service can be done in code or configuration.
'''

Public Class CustomAuthorizationManager
Inherits ServiceAuthorizationManager

Protected Overloads Overrides Function CheckAccessCore(ByVal operationContext As OperationContext) As Boolean

'For mex support (starting WCF service, etc.)
'NOTE: Other than for service startup this will NOT be true because the WCF
'configuration dictates that WindowsCredentials must be sent and Anonymous users
'are NOT allowed.
If operationContext.ServiceSecurityContext.IsAnonymous Then
Return True
End If

'If Windows Authentication has been defined in the binding and either of the (2)
'predefined AppSettings are populated, proceed to authorize current user/group against allowed users or groups.
If (ConfigurationManager.AppSettings("AuthorizedGroups") IsNot Nothing) OrElse _
(ConfigurationManager.AppSettings("AuthorizedUsers") IsNot Nothing) Then

Dim IdentityIsAuthorized As Boolean = False

'Extract the identity token of the current context user making the call to this service
Dim Identity As WindowsIdentity = operationContext.ServiceSecurityContext.WindowsIdentity
'Create a WindowsPrincipal object from the identity to view the user's name and group information
Dim Principal As New WindowsPrincipal(Identity)

'Prior to proceeding, throw an exception if the user has not been authenticated at all
'if the 'AppSettings' section are populated indicating the Windows Authentication should be checked.
If Identity.IsAuthenticated = False Then
Throw New SecurityTokenValidationException("Windows authenticated user is required to call this service.")
End If

'Define (2) string arrays that will hold the values of users and groups with permitted access from the .config file:
Dim AuthorizedGroups As String() = Nothing
Dim AuthorizedUsers As String() = Nothing

'Procced to check the AuthorizedGroups if defined, against the current user's Groups
If ConfigurationManager.AppSettings("AuthorizedGroups") IsNot Nothing Then
'The values in the .config are separated by a comma, so split them out to iterate through below:
AuthorizedGroups = ConfigurationManager.AppSettings("AuthorizedGroups").ToString().Split(",")

'Iterate through all of the permitted groups from the .config file:
For Each Group As String In AuthorizedGroups
'If the user exists in one of the permitted Groups from the AppSettings "AuthorizedGroups" values,
'then set value indicating that the user Is Authorized.
If Principal.IsInRole(Group) Then IdentityIsAuthorized = True
Next

End If

'Procced to check the AuthorizedUsers if defined, against the current user's name
If ConfigurationManager.AppSettings("AuthorizedUsers") IsNot Nothing Then
'The values in the .config are separated by a comma, so split them out to iterate through below:
AuthorizedUsers = ConfigurationManager.AppSettings("AuthorizedUsers").ToString().Split(",")

'Iterate through all of the permitted users from the .config file:
For Each User As String In AuthorizedUsers
'If the user exists as one of the permitted users from the AppSettings "AuthorizedUsers" values,
'then set value indicating that the user Is Authorized.
If Identity.Name.ToLower() = User.ToLower() Then IdentityIsAuthorized = True
Next

End If

'Return the boolena indicating if the user is authorized to proceed:
Return IdentityIsAuthorized
Else

'Call the base class implementation of the CheckAccessCore method to make authorization decisions
'since no defined users or groups were defined in this service's .config file.
Return MyBase.CheckAccessCore(operationContext)

End If

End Function

End Class

Notice from the code above, that we have defined (2) key values which of at least (1) must exist for the code above to work. The appSettings sections are named: AuthorizedGroups and AuthorizedUsers. Below is a sample configuration using both of these values:






In addition to the overridden method and appSettings values, we must configure the WCF behavior for our service to indicate the Service Authorization Manager name as displayed below:














You also need to specify within the binding that the clientCrendentals are of type 'Windows'. To show the node fully, I have included the full 'Security' node in which I was using Transport security, but this can be configured for your needs and is not specific to this procedure:







That will be everything you need to 'intercept' the authorization calls to your WCF service and scrutinize the users permitted. Want to see it work? The easiest way to test this is to build a WCF Service and add the code from this article into or above the Service1 default class that is generated from VS.NET. Once your WCF will compile, start the service locally (no need to install) and place a breakpoint on the 1st line in the 'CheckAccessCore()' method. You will be able to tell if the WCF service starts because service client dialog window will display with the methods in your test service. If you leave the default generated code in the service, it exposes (2) methods: GetData() and GetDateUsingDataContract().

To test this all out I created a test ASP.NET web application and consumed the WCF service. Make sure the service is running when attempting to consume it. You can find the link to consume your service in the WCF Service dialog window. For my test project, mine happend to be net.tcp://localhost:8731/Design_Time_Addresses/WcfServiceWindowsSecurityTest/Service1/mex

Once consumed, I added a little bit of code to test as shown below:


Dim wcfSecurityTest As New WindowsSecurityService.Service1Client
'Obviously NEVER hardcode credentials like the example ONLY below
wcfSecurityTest.ClientCredentials.Windows.ClientCredential = New System.Net.NetworkCredential("jsmith", "testpassword", "MyCompany")
'Upon making the call below, the WCF will call the overriden CheckAccessCore() method to allow or reject authorization:
wcfSecurityTest.GetData(2)

When calling the 'GetData()' method above and having a break point in the running WCF service, you will notice the WCF service hit the breakpoint in our 'CheckAccessCore()' method (pretty cool). From here you can debug the method and see how it works.

Hopefully this gets you back to enabling whole application Windows Authentication on your WCF services!

Sunday, December 13, 2009

Running a Periodic Process in .NET using a Windows Service

The need does arise from time to time (literally) to process some repeated task in .NET. This question comes up a lot and about the best way of solving this problem. Should I poll repeatedly? Do I use a timer? What kind of timer should I use? etc...

Usually this question comes up when the need arises to do any of the following examples: checking for new information, reporting, sending emails, updating content on a screen, maintenance, and the examples go on and on.

I prefer to relegate this type of task to a Windows Service. The service can be created using Visual Studio .NET and then installed on your machine or server. The service is always running (once started) and provides a good mechanism for preforming repeated background tasks like periodic execution.

After doing research on this topic myself, I have found the best way to have a process run on a set time interval is to use a 'ThreadPool.RegisterWaitForSingleObject' from the System.Threading namespace. As from the
MSDN on this method: "Registers a delegate to wait for a WaitHandle, specifying an integer for the time-out in milliseconds."

The 'RegisterWaitForSingleObject' method registers a delegate to wait for a WaitHandle, specifying a timeout. It allows this service to tell the thread pool, "Hey, could you call me when this object is signalled or the timeout has elapsed? Thanks." The method queues the specified delegate to the thread pool (The thread pool uses background threads). A worker thread will execute the delegate when one of the following occurs:


-The specified object is in the signaled state.
-The time-out interval elapses.

This method will repeatedly call the delegate each time the timespan value has elapsed, or until the 'Unregister' method has been called. The callback method registered can do anything you need. The actual method will probably be local to the service, but from there you could make a call to a .dll, WCF or .asmx service, etc. to reuse existing functionality that may already exist. You just need the Windows Service to the the work of waking up every so often to do some work.

You can implement 1:many of these delegates to run as few or as many repeated tasks from within a Windows Service. I must give credit to the following Blog entry which really helped get me started with using this method: Periodic Execution in .NET <<--Code

The blog link above has a terrific easy to follow code example with explanations of implementing the RegisterWaitForSingleObject within a Windows Service, so I will not duplicate it here. I will just say that I myself have implemented the code and expanded on it, and can say that this is a great way to handle repeated processing of a task on a set time interval.

And lastly, you might be saying "I don't know how to create and use a Windows Service in .NET!". Well to get you going on that (there are quite easy by the way to get up and running), check out the following site:

Walkthrough: Creating a Windows Service Application in the Component Designer

Saturday, December 12, 2009

How To: Bind an Enum to an ASP.NET DropDownList

Enumerations are a great way to categorize and structure a set of data within your application, and is usually a 'next step' or improvement at times from hardcoding miscellaneous values throughout an application. Some examples of using an enumeration might be for month names, credit card types accepted, colors, season names, file formats, and the examples are endless.

You may find that you need or want to bind that enumeration directly to a control such as an ASP.NET DropDownList. The DropDownList is obviously an easy fit for an enumeration as it uses a key-value pair style of data for its 'Text' and 'Value' attributes which align to an enumeration's member name and initializer attributes.

For all of the following examples, we will work with the following simple enumeration using 'Months of the Year' (yes, it may be possible to get this same info by looping through a DateTime object and adding 1 month to each iteration, but this is just to show a basic example of a simple enumeration type):

Public Enum Months
January = 1
February = 2
March = 3
April = 4
May = 5
June = 6
July = 7
August = 8
September = 9
October = 10
November = 11
December = 12
End Enum

Accomplishing this task can be done in so many ways. One way is to directly bind just the enum member values to a DropDownList without its associated name. This may acceptable in the situation of months in the year where only the actual integer value is needed. This code to bind just the values is displayed below:

'Populate the months dropdown (from Enumeration)
Dim tEnumMonths As Type = GetType(Months)
Me.ddlMonths.DataSource = System.Enum.GetValues(tEnumMonths)
Me.ddlMonths.DataBind()
'Insert blank '0' value at beginning of DropDown
Me.ddlMonths.Items.Insert(0, New ListItem(" "))

However, most of the time you will probably find that you want to bind both the member name and its associated value. This way you can display to the user a description and extract its value server side for storing in a database, processing business rules, etc. In this case we need to transform or port the enumeration data from the enum type into a bindable object type to the ASP.NET DropDownList. There are so many bindable types; a few examples are: DataSet, DataTable, DataView, Array, ArrayList, HashTable, Object Collection (Generics), and many more.

In the following I will focus on (3) additional methods. All will involve calling a Shared function in a 'Utilities' call that is accessible by all of the UI. This type functionality is not specific to any specific object and holds no concise responsibility other than being a 'Helper' function. Therefore these methods are Shared and do not require class instantiation to access.

The 1st method will take the DropDownList in question and the Enum type as parameters and perform all of the work necessary to bind the data. This method is a full on binding method specific to an ASP.NET DropDownList, so in that sense it is quite powerful, but offers not much reuse beyond binding to this control type.

Public Shared Sub BindDDLToEnum(ByVal EnumType As Type, ByVal DropDown As UI.WebControls.DropDownList, ByVal InsertBlankZeroValue As Boolean)

'Get the Name (String) values from the Enum
Dim EnumNames As String() = System.Enum.GetNames(EnumType)

'Get the Values (Integer) from the Enum
Dim EnumValues As Array = System.Enum.GetValues(EnumType)

'If the caller requested a blank entry with a value of 0 entered, do that now.
If InsertBlankZeroValue Then
'Add a space and a '0' value at the beginning
DropDown.Items.Add(New Web.UI.WebControls.ListItem(" ", 0))
End If

'Loop through the Enum values and add the name,value pair to a 'ListItem' object to be directly inserted into the DropDownList
For i As Integer = 0 To EnumNames.Length - 1
DropDown.Items.Add(New Web.UI.WebControls.ListItem(EnumNames(i), Integer.Parse(EnumValues.GetValue(i))))
Next

'If a blank '0' value was entered, make sure it is the default selected item. This is important
'for RangeValidator controls and the like to pick up on and validate against.
If InsertBlankZeroValue Then
DropDown.ClearSelection()
DropDown.Items.FindByValue(0).Selected = True
End If

End Sub

As you can also see above, I chose to add an additional boolean parameter named 'InsertBlankZeroValue'. This value dictates if a blank string with a '0' value is inserted as the 1st element in the DropDownList. This functionality could easily be modified, removed, or even expanded (i.e. take additional parameters specifying default name and value rather than '0' and blank) to suit your individual needs.

Now you may want to make some more abstract methods that transform the Enum into a bindable type, but don't want to bind it immediately to a control. In this case I have made (2) more sample methods that simply take the Enum type and return a key-value pair object. The 1st method returns a HashTable as shown below:

Public Shared Function GetHashTableFromEnum(ByVal EnumType As Type) As Hashtable

'Get the Name (String) values from the Enum
Dim EnumNames As String() = System.Enum.GetNames(EnumType)

'Get the Values (Integer) from the Enum
Dim EnumValues As Array = System.Enum.GetValues(EnumType)

'Declare a HashTable to hold the Enum name,value pairs
Dim ht As New Hashtable()

'Loop through all of the name,value pairs in the Enum and add them as new elements to the HashTable
For i As Integer = 0 To EnumNames.Length - 1
ht.Add(EnumNames(i), Integer.Parse(EnumValues.GetValue(i)))
Next

Return ht

End Function

The main issue you will note about the method above is that the HashTable returned will indeed have the enum values in a key-value format but they will not be in the order that they were within the Enum. Typically this is an unwanted result. This class could be expanded to implement an ICompare interface and expose a sorting routine to then sort the HashTable values. However, other object types will give us this functionality with built in ability.

The last type I wrote a Utilities method for that solves the sorting issue is by returning a 'DataTable' object from the Enum type passed in as an argument. Once the DataTable is created by making a table with (2) columns named "key" and "value", we can create a DataView from it using the sort we specify and then return a DataTable type back from the DataView. The code for this is shown below:

Public Shared Function GetDataTableFromEnum(ByVal EnumType As Type) As DataTable

'Get the Name (String) values from the Enum
Dim EnumNames As String() = System.Enum.GetNames(EnumType)

'Get the Values (Integer) from the Enum
Dim EnumValues As Array = System.Enum.GetValues(EnumType)

'Declare a new DataTable with column names "key" and "value"
Dim dt As New DataTable()
dt.Columns.Add("key", GetType(String))
dt.Columns.Add("value", GetType(Integer))

'Loop through all of the name,value pairs in the Enum and add them as new rows to the DataTable
For i As Integer = 0 To EnumNames.Length - 1
Dim dr As DataRow = dt.NewRow
dr("key") = EnumNames(i)
dr("value") = Integer.Parse(EnumValues.GetValue(i))
dt.Rows.Add(dr)
Next

'Sort the DataTable by the value column
Dim dv As DataView = dt.DefaultView
dv.Sort = "value asc"

'Apply the sorted DataView back to the DataTable to be returned
dt = dv.ToTable()

Return dt

End Function

Once again it is important to note that this method is just a base example and could be customized easily to fit your needs. As you can see above, the method automatically sorts based on the "value" column in ascending order. You could add parameters to the method that could dictate the sort. And you could also change this method and just have the DataView returned rather than extracting a DataTable back out of it. Both types can be used as the DataSource for a control like an ASP.NET DropDownList.

Below is the code used to make the call to the Utilities class and have it bound to our 'Months' enumeration.

'Option 1: Bind the DropDownList immdeatly to the Enum type
Utilities.BindDDLToEnum(GetType(Months), Me.ddlMonths, True)

'Option 2: Get a HastTable back from the Enum, and use it however needed:
Dim MyHt As New Hashtable()
MyHt = Utilities.GetHashTableFromEnum(GetType(Months))

'Option 3: Get a DataTable back and then bind on the columns named "key" value"
Dim MyDt As New DataTable
MyDt = Utilities.GetDataTableFromEnum(GetType(Months))
'Set the Text and Value properties which correspond to the "value" and "key" elements
'of the DataTable object created and populated above
Me.ddlMonths.DataTextField = "key"
Me.ddlMonths.DataValueField = "value"
'Set the DataSource Bind the DataView to the passed in DDL control
Me.ddlMonths.DataSource = MyDt
Me.ddlMonths.DataBind()

Lastly is a picture of the bound ASP.NET DropDownList:

The main purpose of this was just to get you as the developer started when needing to bind an Enum to a control like an ASP.NET DropDownList. You can easily expand or modify any of the methods to suit your needs providing the most streamlined use and reusability for your application.

Tuesday, November 17, 2009

.NET Object Collections Using Generics 101

Since the .NET Framework 2.0, we have had the ability to use Generics from the System.Collection.Generic namespace to create a strongly typed list of objects. Some might be saying, "Well what is that?" It is a great way to take a single instance of an object and add it to a 'list' where additional object instances can be added as well. It is basically an ArrayList of objects.

So the next question might be, "Well why do I need that?" Think of another common way to organize relation data using a non-strongly type traditional DataSet. A DataTable within a DataTable has rows and columns. Typically to reference a value within that DataSet we might have a line of code similar to the following:


Dim MyValue As String = ds.Tables("MyTable1").Rows(0).Item("FirstName").ToString()

Now that does work, however that is a lot of hardcoding and can be difficult to keep up with. Especially on a multi developer project. Imaging trying to remember all of those column names if that DataSet was passed back to the UI to be bound to a control or populate others. This is where a nice entry point into a list of objects arises. Of course developers could comment on the several reasons using lists of objects is advantageous, but I will take the approach to a developer that is using native ADO.NET objects to do the same thing.

I will provide a simple example to help beginners understand how to put together a list of objects using the 'List(of T)' class. First let's start by looking at the following simple class named 'Customer':


Public Class Customer

Private mFirstName As String = String.Empty
Private mLastName As String = String.Empty
Private mID As Integer = 0

Public Sub New()
'Default class Constructor
End Sub

Public Property FirstName() As String
Get
Return mFirstName
End Get
Set(ByVal value As String)
mFirstName = value
End Set
End Property

Public Property LastName() As String
Get
Return mLastName
End Get
Set(ByVal value As String)
mLastName = value
End Set
End Property

Public Property ID() As Integer
Get
Return mID
End Get
Set(ByVal value As Integer)
mID = value
End Set
End Property

Public Function ShowFullName() As String
'Simple class method; just for show
Return Me.FirstName + Me.LastName
End Function

End Class

Now at this point we may have received multiple rows back from the database containing data with the elements mapping to the properties above. Previously, we could have placed this data into a DataSet to pass back to the UI as mentioned before. This time we are going to build up a list of objects to use. Now in this case you may still have used an ADO.NET DataAdapter to get the data from a stored procedure and it is currently in a DataTable object. No problem, now is the time to place that data into an object instance (1 DataRow = 1 Object of type Customer) and then add that to the list. Let's take a look how that is done below:


'Create an Customer Object
Dim MyCustomer As New Customer()
'Create a List of objects of type Customer
Dim MyCustomerLst As New List(Of Customer)
'Iterate through the data returned in the DataTable
For Each dr As DataRow In dt.Rows

'Create a new instance of the Customer object to place this iterations values
MyCustomer = New Customer()

'Add the data to the object's properties
If Not IsDBNull(dr("FirstName")) Then MyCustomer.FirstName = dr("FirstName")
If Not IsDBNull(dr("LastName")) Then MyCustomer.LastName = dr("LastName")
If Not IsDBNull(dr("CustomerID")) Then MyCustomer.ID = dr("CustomerID")

'Add the single object instance created above to the 'List' of objects
MyCustomerLst.Add(MyCustomer)
Next

At this point the object collection named 'MyCustomer' can be passed around your application's layers as a type of 'List(of Customer)'. For example take a look to the following method that takes the list as a parameter, and then loops through it to use its values:


Public Function GenerateCustomerList(ByVal CustomerLst As List(Of Customer)) As String

Dim sb As New StringBuilder

'Iterate through each 'Customer' object instance in the List(of Customer) passed into method:
For Each SingleCustomer As Customer In CustomerLst

'Build a String in the format of: John Smith ID: 1234
sb.AppendLine(SingleCustomer.FirstName + " " + SingleCustomer.LastName + " ID: " + SingleCustomer.ID.ToString())

Next

'Return the appended String
Return sb.ToString()

End Function

So as you can see we were able to iterate through the object collection and being able to refer to the values by object property name rather than a hardcoded value representing the original column named returned from the database. One might say in the example above that we did at one point reference the column name when adding the data to the 'Customer' object instance. Yes, that is true but with this methodology you need only to reference it once and the location of that reference is typically at a low level either in the DAL or at the bottom of the BLL depending on your design. Therefore, if there were database changes that affected those names, they could be changed in one place rather than scattered throughout the UI and entire application.

Passing around a list of objects is much preferable to passing around traditional ADO.NET objects in many situations. Also, there are other types that may have been used similarly that could also be replaced using object collections. An example could be an Array or ArrayList. In fact performance wise, object collections are very good. Read the following excerpt from the MSDN:

"In deciding whether to use the List(Of(T)) or ArrayList class, both of which have similar functionality, remember that the List(Of(T)) class performs better in most cases and is type safe."

There are so many uses for a list of objects, and this entry was just to describe one usage and to provide the developer new to using the List(of T) class some ideas on how they may expand on it. Once you begin to harness the power of OOP and the basic component of it: the class, you will discover an entire new set of powerful tools the .NET Framework offers as discussed here using a List(of Customer).

***UPDATE*** You can imporve this code one step further by using LINQ to populate the list of objects directly rather than manually looping through each DataRow. To see the code look the post of mine from the link below:

How To: Populate a List of Objects from a DataSet Using LINQ

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.